4

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

例子:

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 的类型是“无效”,我希望调用第二个 Call。否则第一个。VS 它工作正常,但 GCC 到处都是。它总是调用第一个。现在这是在非专业类中专攻的问题,还是与我专攻“无效”这一事实有关

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

4

1 回答 1

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>,否则调用第一个,因为第一个不那么特别。

也可以使用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是 void,则采用第二个,如果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,那么它会使其::typetypedef 不存在。在案例类型不同的情况下is_same派生自。false_type然后我们会尝试访问一个不存在的名称——这是一个无效的结构,因此也会导致 SFINAE 失败。

于 2009-04-09T15:50:57.077 回答