模板类中函数的模板特化

时间:2009-04-09 15:43:08

标签: c++ function templates 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 ) {
   }
};

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

任何帮助都会很棒。感谢。

1 个答案:

答案 0 :(得分: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>) { }

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

也可以使用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) { }

现在,如果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) { }
如果模板参数的替换产生无效的类型或构造,则会发生

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

在上面的enable_if案例中,它的工作方式不同。如果enable_if被赋予从false_type派生的内容,则会使其::type typedef不存在。 is_same在案例类型不同的情况下从false_type派生出来。然后我们会尝试访问一个不存在的名称 - 这是一个无效的构造,因此也会出现SFINAE故障。

相关问题