不实例化具有默认模板参数的模板结构

时间:2015-07-25 07:44:36

标签: c++ templates template-specialization default-arguments

假设我有这段代码

template<typename T2, typename T = int>
struct X
{
    static double f;
};

template<typename T>
double X<T>::f = 14.0;

如果我尝试编译clang,请给我以下错误

  

声明的嵌套名称说明符'X ::'不引用a   类,类模板或类模板部分特化

和GCC:

  

错误:非模板'double X :: f'

的模板定义

问题是:

为什么编译器希望我们像这样专门化struct X:

template<typename T2>
struct X<T2,int>
{
    static double f;
};

第一个声明有int作为默认参数,为什么编译器不选择这个声明?

我搜索了standard锚[temp.spec],但没有帮助。

在SO {

>上回答one之后,我问了这个问题

感谢您的帮助!

1 个答案:

答案 0 :(得分:8)

“为什么编译器希望我们像这样专门化struct X” - 这不是错误消息所说的。你不需要来做这件事,你真的不应该这样做,除非你想要的是部分特化和仅为该部分特化定义的静态成员。

问题是template<typename T2, typename T = int> struct X是一个具有两个模板参数的类模板。第二个具有默认模板参数的事实不会改变仍然存在两个参数的事实。

因此,您需要将类模板成员定义为属于具有两个参数的类模板,如下所示:

template<typename T2, typename T>
double X<T2, T>::f = 14.0;

标准中的相关段落(N4527,当前草案):

[14.5.1p3]

  

当一个成员函数,一个成员类,一个成员枚举,一个静态   定义数据成员或类模板的成员模板   在类模板定义之外,成员定义是   定义为 template-parameters 所在的模板定义   那些类模板。使用的模板参数的名称   在成员的定义中可能与模板不同   类模板定义中使用的参数名称。模板   成员中的类模板名称后面的参数列表   定义应按与所用参数相同的顺序命名参数   在成员的模板参数列表中。每个模板参数   pack应在模板参数列表中使用省略号进行扩展。

[14.1p9]

  

[...]默认 template-argument 不得在。中指定    template-parameter-lists 类成员定义   出现在成员班级之外的模板。 [...]

如上面引用中所述,模板参数(T2T)的实际名称无关紧要,它们可能与类模板定义中的不同,但它们不同需要在成员的定义内保持一致。也就是说,你可以这样做

template<typename T, typename U>
double X<T, U>::f = 14.0;

它仍然会定义正确的X类模板的成员。但是,使用相同的名称可以使您在阅读代码时更容易理解。

通过在原始示例中定义f之前定义部分特化,template<typename T> double X<T>::f = 14.0;成为部分特化f的成员template<typename T2> struct X<T2,int>的有效定义,并且只有那个模板(部分特化是模板本身)。主模板f的成员template<typename, typename> struct X仍未定义。

相关措辞见[14.5.5.3p1]:

  

类模板partial的成员的模板参数列表   specialization应匹配类的模板参数列表   模板部分专业化。 a的模板参数列表   类模板部分特化的成员应匹配   模板参数列表的类模板部分特化。一个   类模板特化是一个独特的模板。的成员   类模板部分特化与成员无关   主要模板。 [...]