不允许在
void*
类型的非类型模板参数 至少是该标准的某些版本。
这是真的吗?
如果是这样,则在哪个版本的标准中不允许使用void*
类型的非类型模板参数?
(注意:如
a comment
回答
another comment,
这是关于非类型模板参数的,
不是模板类型参数,
可以是每个有效的 type-id
[temp.arg.type],
包括void*
。
答案 0 :(得分:11)
void*
类型的模板参数自C ++ 20起有效。
它们在C ++ 20之前无效。
C ++ 20放宽了对非类型模板参数类型的限制, 因此,我们首先对其进行调查。
当前草案(截至UTC 2019年5月6日10:00)在[temp.param]/4中表示:
非类型 template-parameter 必须具有以下之一 (可选,具有简历资格)类型:
- 具有强结构等式([class.compare.default])的文字类型,
- 左值引用类型
- 包含占位符类型([dcl.spec.auto])的类型,或
- 推导类类型([dcl.type.class.deduct])的占位符。
void*
是指针类型。
指针类型是标量类型([basic.types]/9)。
标量类型是文字类型([basic.types]/10)。
因此,void*
是文字类型。
第一颗是相关的。
进一步跟踪,[class.compare.default]/3说:
如果给定
C
的glvalue为x
,则类型const C
具有强结构相等性 输入C
,或者:
- 的有效表达式
x <=> x
是非类类型,而std::strong_ordering
是类型std::strong_equality
或C
或
==
是一个类类型,其C
运算符定义为x == x
的定义中的默认值,bool
在上下文中格式正确C
的所有基类子对象都转换为C
,并且是非静态的 数据成员具有很强的结构平等性,并且mutable
没有volatile
或void*
子对象。
x <=> x
是非类类型,
所以第一个项目符号是相关的。
现在,问题归结为x
的类型
其中void* const
是类型const void*
(不是p <=> q
)的glvalue。
根据{{3}}:
如果复合指针类型为对象指针类型,则
std::strong_ordering
为p
类型的。如果两个指针操作数q
和p <=> q
比较等于([expr.eq]),std::strong_ordering::equal
得出p
;如果q
和p <=> q
比较不相等,则std::strong_ordering::less
得出q
,如果p
比较大于std::strong_ordering::greater
和p
如果q
比较大于void*
([expr.rel])。否则,结果不确定。
请注意,x <=> x
是对象指针类型([expr.spaceship]/8)。
因此,std::strong_ordering
的类型为void*
。
因此,类型void*
具有强结构相等性。
因此,在当前的C ++ 20草案中,
模板参数类型可以使用std::nullptr_t
。
现在,我们解决C ++ 17问题。 [basic.compound]/3说:
非类型 template-parameter 必须具有以下之一 (可选,具有简历资格)类型:
- 整数或枚举类型
- 指向对象的指针或指向函数的指针,
- 对对象的左值引用或对函数的左值引用
- 成员的指针,
void*
或- 包含占位符类型的类型。
请注意,“指向对象的指针”不包含void
每[temp.param]:
[注意:”指向
void
的指针没有指向对象的指针类型,因为void*
不是对象类型。 — 尾注]
以上六个项目符号均不包含void*
作为模板参数的可能类型。
因此,在C ++ 17中,
模板参数的类型不得为void*
。
C ++ 11和C ++ 14的措辞相同
除了不存在有关占位符类型的项目符号。
一般来说,
在C ++ 20之前,
模板参数的类型不得为template <void*>
class C {};
C<nullptr> x;
。
[basic.compound]/3在 T.C. 没有人诊断出这个IHRC。 让我们测试一下编译器是否在C ++ 17模式下进行诊断 并显示以下最小示例:
arules
代码在以下位置编译并运行良好 comment, GCC 9.1.0, GCC 8.3.0, GCC 7.3.0, GCC 6.3.0, GCC 5.5.0, Clang 8.0.0, Clang 7.0.0, 和Clang 6.0.1。
因此,TC的说法是正确的。