1

我看过许多 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;
}

从我的代码示例中的注释可以看出,当在类声明中提供了专用函数的定义时,代码构建没有错误,并且运行成功,并且nin function的main()值为1,正如预期的那样。

但是,当将专用函数定义移到类声明之外,但保持不变时,如图所示,编译器会发出其他帖子已经指出的错误;就我而言(Visual Studio 2010),错误是an explicit specialization of a template member must be a member of an explicit specialization.

我的问题是这个。如果除非封闭的模板类也是特化的,否则不允许在类模板中显式特化成员函数,那么如果在类声明中提供了定义,为什么它在我的示例代码中起作用?

4

1 回答 1

3

由于不同的原因,这两个版本都不应该编译。

在第一种情况下,特化必须存在于命名空间级别,这意味着编译器应该拒绝在类定义中提供的特化。

在第二种情况下,特化的位置是正确的,但要提供成员函数的特化(函数的特化必须始终是完整的,绝不是部分的),您还需要修复封闭的模板类参数。也就是说,无论使用哪种类型,都不能专门化foo一种类型,并用于实例化封闭模板。您可以(可能不是您想要的)提供固定所有参数的专业化:XT1T2

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 );
   }

这样,您可以将仅返回类型上的模板转换为对重载函数的调用,并且可以让编译器为您解决问题。

于 2012-06-18T15:18:30.703 回答