(基于问题评论中的讨论)
注:
我参考的是C++17或接近的答案。C++14的工作原理是一样的,文本差异在答案的末尾。
void()
[表达式类型转换]
,重点矿山:
1安
简单型规格
(7.1.7.2)或
类型名称规范
(14.6)
后跟带括号的可选选项
表达式列表
或通过
(初始化器)构造给定初始化器的指定类型的值。如果类型是推导类类型的占位符,则在本节的其余部分,它将被重载解析为类模板推导(13.3.1.8)选择的函数的返回类型替换。
2如果初始值设定项是一个带圆括号的单个表达式,则类型转换表达式与相应的转换表达式(5.4)等效(在dened中,如果dened在意义上)。
如果类型是(可能是cv限定的)void,初始值设定项是(),则表达式是指定类型的prvalue,不执行初始化。
否则,表达式是指定类型的prvalue,其结果对象由初始值设定项直接初始化(8.6)。对于T()形式的表达式,T不应是数组类型。
作废()
只有在
[表达式类型转换]/2
像
无初始化
.
void{}
不符合该异常,因此它尝试成为
直接初始化
对象
tl;博士
此处通过C++14注释:您不能
直接初始化
一
void
对象
兔子钻穿N4618 8.6
[dcl.init]
空白{}
-
8.6/16=>;
直接初始化
-
8.6/17.1=>;
列表已初始化
-
8.6.4/3.10=>;
值已初始化
-
作废()
将以8.6/11=>为上述三项设置快捷方式;
值已初始化
,然后重新加入小径,这就是为什么
[表达式类型转换]
是必需的。
-
8.6/8.4=>;
现在,8.6/6定义了
零初始化
适用于:
4618号3.9
[基本类型]/9
定义
标量
:
算术类型(3.9.1)、枚举类型、指针类型、指向成员的指针类型(3.9.2)、,
标准::nullptr_t
,这些类型的cv限定版本(3.9.3)统称为
标量类型
.
定义
算术类型
:
整体和涂层类型统称为
算术类型
.
所以
无效的
不是
算术类型
,所以它不是
标量
,所以不可能
零已初始化
,所以不可能
值已初始化
,所以不可能
直接初始化
,因此表达式无效。
除了初始化之外,
作废()
和
空白{}
prvalue值
无效的
。即使你不能拥有
结果对象
对于不完整的类型,以及
无效的
是
总是
不完整:
N4618 3.9.1号
[基本基本]/9
(粗体我的):
A.
类型cv void是不完整的类型
无法完成的;这样的类型有一组空值。
decltype
特别允许不完整的类型:
N4618 7.1.7.2号
[解密类型简单]/5
(粗体我的):
如果
脱模硬币
是prvalue,不应用临时物化转换(4.4),也没有为prvalue提供结果对象。
prvalue的类型可能不完整。
在C++14中,N4296 5.2.3
[表达式类型转换]
措辞不同。加括号的形式几乎是加括号的版本之后才想到的:
A.
简单型规格
(7.1.6.2)或
类型名称规范
(14.6)后跟括号
表达式列表
构造给定表达式列表的指定类型的值。如果表达式列表是单个表达式,则类型转换表达式与相应的转换表达式(5.4)等效(在denedness中,如果denedned在意义上)。如果指定的类型是类别类型,则类别类型应完整。如果表达式列表包含多个值,则类型应为具有适当声明的构造函数(8.5,12.1)的类,并且表达式
T(x1, x2, ...)
与声明等效
T t(x1, x2, ...)
; 对于一些发明的临时变量t,其结果是t的值作为prvalue。
表达式T(),其中T是
simple-type-speciï¬er
或
typename-speciï¬er
对于非数组完整对象类型或(可能是cv限定的)
无效的
类型,创建指定类型的prvalue,其值是通过值初始化(8.5)T类型的对象而产生的值;没有对void()案例进行初始化。[
注:
如果
T
是cv限定的非类类型
在确定结果prvalue的类型时被丢弃(第5条)。
尾注
]
同样,a
简单型规格
或
类型名称规范
后跟一个
带括号的init列表
创建一个用specied初始化的specied类型直接列表(8.5.4)的临时对象
带括号的init列表
,其值是作为prvalue的临时对象。
就我们的目的而言,效果是一样的
change
与相关
P0135R1 Wording for guaranteed copy elision through simplified value categories
,它从表达式中删除了临时对象创建。相反,如果上下文需要,表达式的上下文会提供一个由表达式初始化的结果对象。
如上所述,
解密
(不同于
sizeof
或
typeid
)没有为表达式提供结果对象,这就是为什么
作废()
即使它无法初始化结果对象,也能正常工作。
我觉得N4618 5.2.3中的例外
[表达式类型转换]
应适用于
空白{}
也这意味着
{}
变得更复杂。参见示例
ES.23: Prefer the {} initializer syntax
在C++核心指南中,该指南目前建议
decltype(void{})
结束
decltype(void())
.
decltype(T{})
更可能是这个咬你的地方。。。