考虑以下代码片段:
auto f() { return void({}); }
int main() { f(); }
{}
中的void({})
到底是什么?当然只是出于好奇。无论如何,让我们走得更远吧。
请注意,GCC 6.1 和 clang 3.8 编译它都没有错误 (
-std=c++14 -pedantic
)。警告:非类类型的列表初始值设定项不得加括号
使用
-pedantic-errors
代替,GCC 在 clang 编译时以错误结束。
这种差异是两个编译器之一的错误吗?
我的意思是,它是应该接受还是不应该接受的有效代码?
到
void
类型的转换以及返回 void
值的可能性从一开始就存在于 C++ 语言中。唯一引起疑问的部分是 {}
在这种情况下的作用。
使用 clang 进行快速实验
int a({});
生成一条错误消息,指出
error: cannot initialize a variable of type 'int' with an rvalue of type 'void'
这表明 clang 将
{}
解释为 void
值。这似乎是一种不标准的行为。我在语言规范中没有看到任何地方说 {}
应该在这种情况下产生 void
值。
但是由于clang中恰好存在这种情况,所以在clang中编译
void({})
并没有什么异常。 C++ 中的任何值都可以转换为 void
类型,这意味着只要编译器在此上下文中接受 {}
,其余的就自然而然了。
在 GCC 中,这实际上是
-pedantic-errors
模式下的错误
error: list-initializer for non-class type must not be parenthesized
因此,在 GCC 中,它是一个“错误”,而不是“警告”。
这里实际发生的是,打开
({
和关闭 })
的组合使这些编译器将其解释为称为 Statement Expression 的 GNU C 语言扩展(顺便说一下,clang 也支持它)。例如,这就是使以下代码编译的原因
int a = ({ 3; });
在该扩展下,表达式
({})
被视为void
类型的语句表达式。然而,这与 C++ 中的统一初始化语法相冲突。