问题
I have a templated class and inside I have a templated function( different template parameters ) and I having issues getting the compiler to call the correct one.
Example:
template< class Parm1, class Parm2, class Parm3 >
class Class {
public:
void Func( Parm1 arg1, Parm2 arg2 ) {
Call<Parm3>( arg1, arg2 );
}
protected:
template< class Type >
void Call( Parm1 arg1, Parm2 arg2 ) {
}
template<>
void Call<void>( Parm1 arg1, Parm2 arg2 ) {
}
};
So if the type of Parm3 is 'void' I want the second Call to be called. Otherwise the first. VS it works fine but GCC pukes all over it. It always calls the first one. Now is this an issue with specializing within of an unspecialized class or does it have something to do with the fact that Im specializing with 'void'
Any help would be great. Thanks.
回答1:
Yes, explicitly specializing a function without fully specializing all outer template is not possible (an explicit function specialization is a real function - there can't be any "variable parts" around it that are still parameterized by a template)
A simple way is to use a type2type template together with overloading:
template<typename T> struct t2t { typedef T type; };
void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2, t2t<Parm3>()); }
template< class Type, class V > void Call( Parm1 arg1, Parm2 arg2, t2t<V>) { }
template< class Type > void Call( Parm1 arg1, Parm2 arg2, t2t<void>) { }
Now, it will call the second Call
overload if you call it with t2t<void>
, and the first otherwise, because the first one is less special.
Using enable_if is possible too:
void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }
template< class Type > typename disable_if< is_same<Type, void> >::type
Call( Parm1 arg1, Parm2 arg2) { }
template< class Type > typename enable_if< is_same<Type, void> >::type
Call( Parm1 arg1, Parm2 arg2) { }
Now, the second one is taken if Type
is void, and the first one is taken if Type
is something else again. But using a different technique. This one is called SFINAE
. An alternative way, but which again adds one parameter is this - to demonstrate the way SFINAE works:
void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }
template< class Type >
void Call( Parm1 arg1, Parm2 arg2, char(*)[!is_same<Type, void>::value] = 0) { }
template< class Type >
void Call( Parm1 arg1, Parm2 arg2, char(*)[ is_same<Type, void>::value] = 0) { }
SFINAE
happens if the substitution of a template parameter yields to an invalid type or construct. Below, we try to create a pointer to an array of size 0 or 1 respectively. An array of size 0 is not valid, and will cause an SFINAE failure - the corresponding template specialization will not be considered as a call-candidate if it is a function.
In the enable_if
case above, it works different. If enable_if
is given something derived from false_type
, then it makes its ::type
typedef not existent. is_same derives itself from false_type
in the case types are not the same. We would then try to access a not existent name - which is an invalid construct and would therefor be an SFINAE failure too.
来源:https://stackoverflow.com/questions/734797/template-specialization-of-function-inside-of-a-templated-class