【发布时间】:2021-12-20 07:59:59
【问题描述】:
文章“模板参数和模板参数”的“Template non-type arguments”段落指出:
唯一的例外是非类型模板参数的引用 或指针类型和引用或指针的非静态数据成员 键入类类型及其子对象的非类型模板参数 (C++20 起) 不能引用/成为的地址
- 一个临时对象(包括在引用初始化期间创建的一个);
- 字符串文字;
typeid的结果;- 预定义变量
__func__;- 或子对象(包括非静态类成员、基子对象或数组元素)上述之一(C++20 起)。。李>
重点是我的。
下面有一个例子
template<int* p> class X {};
int a[10];
struct S
{
int m;
static int s;
} s;
X<&a[2]> x3; // error: address of array element
X<&s.m> x4; // error: address of non-static member
X<&s.s> x5; // ok: address of static member
X<&S::s> x6; // ok: address of static member
根据引用的语句,在 cmets 中带有单词 error 的行应该可以被支持 c++20 的 c++ 编译器编译,因为 a[2] 和 s.m 既不是临时对象,也不是字符串文字,也不是typeid 也不是预定义的变量 __func__ 也不是上述之一的子对象。其实gcc 11.1编译code没有错误,但是clang 12.0.0编译code有错误。
此外,draft N4835 在第 13.4.2 段中声明了以下内容
非类型模板参数的模板参数应转换为 模板参数类型的常量表达式(7.7)。为一个 引用或指针类型的非类型模板参数,或对于每个 引用或指针类型的非静态数据成员 类类型或其子对象的非类型模板参数, 引用或指针值不应引用或作为地址 (分别):
- 一个子对象 (6.7.2),
- 一个临时对象 (6.7.7),
- 字符串文字 (5.13.5),-(2.4)
typeid表达式 (7.6.1.7) 的结果,或- 预定义的
__func__变量 (9.5.1)。
并包含上述示例。再次强调是我的。
考虑到这个草案,clang 可以正常工作而 gcc 不能,因为 a[2] 和 s.m 是子对象。
深入挖掘。 draft N4878 在第 13.4.3 段中包含以下文本
对于引用或指针类型的非类型模板参数,或者对于 非类型中引用或指针类型的每个非静态数据成员 类类型或其子对象的模板参数,引用 或指针值不应引用或作为地址 (分别):
- 一个临时对象 (6.7.7),
- 一个字符串字面量对象 (5.13.5),
typeid表达式 (7.6.1.8) 的结果,- 预定义的
__func__变量 (9.5.1),或- 上述之一的子对象 (6.7.2)。
并且不包含示例。
本主题开头引用的文本对应于草案 N4878,因此 gcc 可以正常工作,而 clang 不能。
C++20 标准对将子对象用作模板非类型参数有何规定?哪个编译器符合标准?
【问题讨论】:
-
最接近C++20的草案是N4861,也就是has an HTML version here。
标签: c++ language-lawyer c++20