我看过很多StackOverflow帖子,说C ++中的类模板成员函数的特化是不合法的,除非封闭类也是专用的。
然而,另一篇文章似乎表明 可以专门化成员模板函数,只要专门函数的定义出现在模板类的类声明中,如下所示:
template<typename T1, typename T2>
class A
{
public:
template<typename TX> TX foo() {return 0;};
template<> T1 foo<T1>() {return 1;}; // provide the specialization's definition within the class declaration: works
//template<> T1 foo<T1>(); // ... switch to this (and provide the definition below), and it's a compile error
};
// This function definition is only present when the commented-out line of code in the class declaration is used
template<typename T1, typename T2>
template<>
T1 A<T1, T2>::foo<T1>()
{
return 1;
}
int main(void)
{
A<int, double> a;
const int n = a.foo<int>(); // When the definition appears inside the class declaration, n is 1 - it works
return 0;
}
从我的代码示例中的注释中可以看出,当在类声明中提供专用函数的定义时,代码构建没有错误,而且它成功运行,并且n
的值在函数中正如预期的那样,main()
为1
。
但是,当在类声明之外移动专用函数定义时,如果保持相同,如图所示,编译器会发出其他帖子已经指出的错误;就我而言(Visual Studio 2010),错误是an explicit specialization of a template member must be a member of an explicit specialization
。
我的问题是这个。如果不允许在类模板中对成员函数进行显式特化,除非封闭模板类也是专用的,那么如果在类声明中提供了定义,为什么它在我的示例代码中有用呢?
答案 0 :(得分:3)
两个版本都不应该出于不同的原因进行编译。
在第一种情况下,必须在命名空间级别存在特化,这意味着编译器应该拒绝在类定义中提供的特化。
在第二种情况下,专门化的位置是正确的,但是为了提供成员函数的特化(函数的特化必须始终是完整的,从不局部),您还需要修复封闭的模板类参数。也就是说,无论使用哪种类型foo
和X
来实例化封闭模板,您都无法对T1
类型进行专门化T2
。您被允许(可能不是您想要的)提供所有已修复参数的专业化:
template <> template <>
int A<int, double>::foo<int>() { return 5; }
您可以使用的替代方案是:
示例:
// inside class template:
private:
template <typename T> T foo_impl( T* _ ) {...} // generic
T1 foo_impl( T1 * _ ) {...} // concrete
public:
template <typename T> T foo() {
return foo_impl( (T*)0 );
}
这样你只能将返回类型的模板转换为对重载函数的调用,并且你可以让编译器为你解决问题。