Template Specialization of Function inside of a Templated Class

烂漫一生 提交于 2019-12-04 14:31:38

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!