问题
I am encountering the C2783 error with Visual C++ (could not deduce template argument), I have the following test case:
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;
}
When commenting the line
static inline void add(ObjectType* obj, typename SPKSetterPattern<TypeCode,ObjectType,U>::func attrSetter) {}
and uncommenting the line following, the code compiles.
I don't understand why, because for me the second argument of 'helper::add' is still the same...
Thanks for help.
回答1:
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?
来源:https://stackoverflow.com/questions/9649904/could-not-deduce-template-argument-pointer-to-member