没有实例化带有默认模板参数的模板结构
Template struct with the default template argument is not instantiated
假设我有这样的代码
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类成员的定义出现在成员类之外的模板。[…]
如上所述,模板形参(T2
和T
)的实际名称无关紧要,它们可以与类模板定义中的名称不同,但在成员定义中需要保持一致。也就是说,你可以这样做
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成员的模板形参列表特殊化应与类的模板参数表匹配模板部分专门化。的模板实参列表类模板部分特化的成员必须匹配类模板部分专门化的模板参数列表。一个类模板专门化是一个不同的模板。的成员类模板部分特化与成员无关主模板的。[…]
- 使用不带参数的函数访问结构元素
- 将结构字段的类型展开为可变模板参数
- MSVC将仅移动结构参数解释为指针
- 如何使我的 sizeof sum 结构与空参数包一起工作
- 如何传递带有通过引用传递的结构参数的函数?
- 展开可变参数模板结构
- 在类构造函数中定义结构变量的参数
- 如何在方法中传递结构参数
- 我应该在C++中将这些结构用作参数化构造函数吗?
- 带参数的数据结构的全局声明
- C++ 带有默认参数的结构,可选择在构造函数中更改
- C++-将具有引用的长参数列表重构为结构
- 为私有结构定义双参数运算符重载
- 我们可以用参数化构造函数初始化结构的数组吗?
- 关于类的想法 参数结构给定实现
- 重映射模板参数结构
- 从C 调用的编译MATLAB函数的输入参数结构
- 如何实现具有不同参数结构的纯虚拟函数
- 如何在C++中获得可更改的函数参数结构
- 函数参数 -> 结构体成员的 void* 和常量 void* 的解决方案