模板类中函数的模板特化

4 c++ templates function specialization

我有一个模板化的类,里面我有一个模板化的函数(不同的模板参数),我有问题让编译器调用正确的.

例:

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 ) {
   }
};
Run Code Online (Sandbox Code Playgroud)

因此,如果Parm3的类型为"void",我希望调用第二个Call.否则第一个.VS它工作正常,但GCC呕吐了它.它总是称为第一个.现在这是一个专门针对非专业课程的问题,还是与我专注于'void'的事实有关

任何帮助都会很棒.谢谢.

Joh*_*itb 7

是的,明确地专门化一个函数而不完全专门化所有外部模板是不可能的(显式函数专门化是一个真正的函数 - 它周围不能有任何"变量部分"仍然由模板参数化)

一种简单的方法是使用type2type模板和重载:

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>) { }
Run Code Online (Sandbox Code Playgroud)

现在,Call如果你用它来调用它会调用第二个重载,否则它会调用第一个重载t2t<void>,因为第一个不太特殊.

使用enable_if也是可能的:

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) { }
Run Code Online (Sandbox Code Playgroud)

现在,如果Type无效则采取第二个,如果是另一个则采取第一个Type.但使用不同的技术.这个被称为SFINAE.另一种方法,但又添加了一个参数 - 用于演示SFINAE的工作方式:

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) { }
Run Code Online (Sandbox Code Playgroud)

SFINAE如果模板参数的替换产生无效的类型或构造,则会发生.下面,我们尝试分别创建一个指向大小为0或1的数组的指针.大小为0的数组无效,并且会导致SFINAE失败 - 如果它是一个函数,相应的模板特化将不被视为调用候选者.

enable_if上面的例子中,它的工作方式不同.如果enable_if给出了从中派生的东西false_type,那么它的::typetypedef就不存在了.在案例类型不同的情况下is_same派生自己false_type.然后我们会尝试访问一个不存在的名称 - 这是一个无效的构造,因此也会出现SFINAE故障.