void({})中的{}是什么?

sky*_*ack 17 c++ gcc clang language-lawyer c++14

请考虑以下代码段:

auto f() { return void({}); }
int main() { f(); }
Run Code Online (Sandbox Code Playgroud)

什么是完全{}void({})
怎么解释?

当然,只是出于好奇.不管怎样,让我们​​走得更远.

请注意,GCC 6.1和clang 3.8都编译它没有错误(-std=c++14 -pedantic).
后者没有抱怨,前者显示警告:

警告:非类类型的list-initializer不能带括号

使用-pedantic-errors替代,GCC有错误而铛编译结束.

这种差异是否是两个编译器之一的错误?
我的意思是,它是否应该被接受的有效代码?

AnT*_*AnT 15

从一开始,C++语言就已经出现了void键入的转换以及返回void值的可能性.提出问题的唯一部分是{}在这种情况下的作用.

用clang快速实验

int a({});
Run Code Online (Sandbox Code Playgroud)

生成错误消息说

error: cannot initialize a variable of type 'int' with an rvalue of type 'void'
Run Code Online (Sandbox Code Playgroud)

这表明clang解释{}为一个void值.这似乎是一种非标准行为.我没有看到语言规范中的任何地方会说{}应该void在这种情况下产生一个值.

但是因为在clang中恰好就是这种情况,所以在void({})编译时没有什么不寻常的.C++中的任何值都可以转换为void类型,这意味着只要编译器{}在此上下文中接受,其余的就是自然而然的.

在GCC中,它实际上是-pedantic-errors模式中的错误

error: list-initializer for non-class type must not be parenthesized
Run Code Online (Sandbox Code Playgroud)

正式地说这是一个"错误",而不是海湾合作委员会的"警告".


这里实际发生的事情是,打开({和关闭的组合})使得这些编译器将其解释为GNU C语言扩展,称为语句表达式(同样由clang支持).例如,这是使以下代码编译的原因

int a = ({ 3; });
Run Code Online (Sandbox Code Playgroud)

在该扩展名下,表达式({})被视为void类型的语句表达式.但是,这与C++中的统一初始化语法冲突.