是的,在不完全特化所有外部模板的情况下显式特化一个函数是不可能的(显式函数特化是一个真正的函数——它周围不能有任何仍然由模板参数化的“变量部分”)
一种简单的方法是将 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
,那么它会使其::type
typedef 不存在。在案例类型不同的情况下is_same
派生自。false_type
然后我们会尝试访问一个不存在的名称——这是一个无效的结构,因此也会导致 SFINAE 失败。