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

Pum*_*kko 4 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;
Run Code Online (Sandbox Code Playgroud)

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

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

对于海湾合作委员会:

错误:非模板'double X :: f'的模板定义

问题是 :

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

template<typename T2>
struct X<T2,int>
{
    static double f;
};
Run Code Online (Sandbox Code Playgroud)

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

我在标准锚[temp.spec]中搜索但它没有帮助.

我问这个问题后,回答了这个一个对SO.

谢谢你的帮助 !

bog*_*dan 8

"为什么编译器希望我们像这样专门化struct X" - 这不是错误消息所说的.你并不需要做到这一点,和你,除非你想要的是一个局部的专业化和仅适用于部分专门定义的静态成员真的不应该这样做.

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

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

template<typename T2, typename T>
double X<T2, T>::f = 14.0;
Run Code Online (Sandbox Code Playgroud)

标准中的相关段落(N4527,现行草案):

[14.5.1p3]

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

[14.1p9]

[...]默认模板参数不应在出现在成员类之外的类模板成员定义的template-parameter-lists中指定 .[...]


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

template<typename T, typename U>
double X<T, U>::f = 14.0;
Run Code Online (Sandbox Code Playgroud)

它仍然会定义正确的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]:

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