Pregunta

Estoy encontrando el error C2783 con Visual C ++ (no se pudo deducir el argumento de la plantilla), tengo el siguiente caso de prueba:

enum SPKType { A, B, C, D };

template<SPKType TypeCode, class ObjectType, typename U>
struct SPKSetterPattern
{
    typedef void (ObjectType::* func)(U);
};
template<class ObjectType, typename U>
struct SPKSetterPattern<B,ObjectType,U> { typedef void (ObjectType::* func)(U,U); };
template<class ObjectType, typename U>
struct SPKSetterPattern<C,ObjectType,U> { typedef void (ObjectType::* func)(U,U,U); };
template<class ObjectType, typename U>
struct SPKSetterPattern<D,ObjectType,U> { typedef void (ObjectType::* func)(U,U,U,U); };


template<typename ObjectType, SPKType TypeCode>
struct helper
{
    template<typename U>
    static inline void add(ObjectType* obj, typename SPKSetterPattern<TypeCode,ObjectType,U>::func attrSetter) {}
    //static inline void add(ObjectType* obj, void (ObjectType::*attrSetter)(U)) {}
};

class test
{
public:
template<typename ObjType>
void init()
{
    // Supposed to work
    helper<ObjType,A>::add(this, &test::setA);
    //helper<ObjType,B>::add(this, &test::setB);
    //helper<ObjType,C>::add(this, &test::setC);
    //helper<ObjType,D>::add(this, &test::setD);
    helper<ObjType,A>::add(this, &test::setAf);

    // Supposed to fail
    //helper<ObjType,B>::add(this, &test::setBf);
}

test() { init<test>(); }

void setA(int a) {}
void setB(float,float) {}
void setC(int,int,int) {}
void setD(int,int,int,int) {}

void setAf(double a) {}
void setBf(int,double) {}
};

int main()
{
test t;
return 0;
}

Al comentar la línea

static inline void add(ObjectType* obj, typename SPKSetterPattern<TypeCode,ObjectType,U>::func attrSetter) {}

y sin cromentar la línea siguiente, el código compila.

No entiendo por qué, porque para mí el segundo argumento de 'Helper :: agregar' sigue siendo el mismo ...

Gracias por la ayuda.

¿Fue útil?

Solución

You're asking the compiler to do a reverse lookup: to find all specializations on U of SPKSetterPattern and all their definitions of func, find the one definition that matches your actual argument, and then deduce the template arguments as those used for that specialization.

It doesn't work like that.

You don't get reverse lookup for template matching.


EDIT: due to requests in comment:

The following code deduces the argument type for a method with all arguments of the same type, and known result type void and class Class:

template< class Class, class MethodPtr >
struct ArgType;

template< class Class, class Arg >
struct ArgType< Class, void (Class::*)( Arg ) >
{ typedef Arg T; };

template< class Class, class Arg >
struct ArgType< Class, void (Class::*)( Arg, Arg ) >
{ typedef Arg T; };

template< class Class, class Arg >
struct ArgType< Class, void (Class::*)( Arg, Arg, Arg ) >
{ typedef Arg T; };

template< class Class, class Arg >
struct ArgType< Class, void (Class::*)( Arg, Arg, Arg, Arg ) >
{ typedef Arg T; };

The original code can then be amended as follows:

template<typename ObjectType, SPKType TypeCode>
struct helper
{
    template< typename U >
    static void ungoodAdd(
        ObjectType*                                             obj,
        typename SPKSetterPattern<TypeCode,ObjectType,U>::func  attrSetter
        )
    {
        (void)obj; (void)attrSetter;
    }

    template< typename MethodPtr >
    static void add(
        ObjectType*     pObject,
        MethodPtr       method
        )
    {
        typedef typename ArgType< ObjectType, MethodPtr >::T Arg;
        ungoodAdd<Arg>( pObject, method );
    }

    // template<typename U>
    // static inline void add(ObjectType* obj, typename SPKSetterPattern<TypeCode,ObjectType,U>::func attrSetter) {}
    //static inline void add(ObjectType* obj, void (ObjectType::*attrSetter)(U)) {}
};

However, with access to some C++11 support probably std::function is a better alternative?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top