没有实例化带有默认模板参数的模板结构

Template struct with the default template argument is not instantiated

本文关键字:参数 结构 默认 实例化      更新时间:2023-10-16

假设我有这样的代码

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

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

嵌套名称说明符'X::'声明不指向类、类模板或类模板局部特化

对于GCC:

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

问题是:

为什么编译器要我们这样专门化结构体X:

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

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

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

我在SO上回答了这个问题后问这个问题。

感谢您的帮助

"为什么编译器要我们这样专门化结构体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]

当成员函数、成员类、成员枚举、静态时定义数据成员或类模板的成员模板在类模板定义之外,成员定义是定义为模板定义,其中模板参数是类模板的那些。所用模板参数的名称在定义成员时可以与模板不同类模板定义中使用的形参名。模板成员中类模板名后面的实参列表定义中参数的命名顺序应与使用的顺序一致在成员的模板参数列表中。每个模板参数在模板参数列表中,应该使用省略号展开。

14.1 (p9)

[…默认的模板参数不能在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;成为部分专门化template<typename T2> struct X<T2,int>的成员f的有效定义,并且仅是该模板的有效定义(部分专门化本身就是模板)。主模板template<typename, typename> struct X的成员f仍然未定义。

相关表述见[14.5.5.3p1]:

类template partial成员的模板形参列表特殊化应与类的模板参数表匹配模板部分专门化。的模板实参列表类模板部分特化的成员必须匹配类模板部分专门化的模板参数列表。一个类模板专门化是一个不同的模板。的成员类模板部分特化与成员无关主模板的。[…]