【问题标题】:What's {} in void({})?void({}) 中的 {} 是什么?
【发布时间】:2017-04-29 03:30:18
【问题描述】:

考虑以下 sn-p:

auto f() { return void({}); }
int main() { f(); }

void({}) 中的 {} 到底是什么?
它是如何解释的?

当然,只是出于好奇。无论如何,让我们走得更远。

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

警告:非类类型的列表初始化器不能用括号括起来

使用 -pedantic-errors 代替,GCC 在 clang 编译时以错误结束。

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

【问题讨论】:

  • 在某些语言中,它表示一个空表或列表。但是,在基于类型的语言中,它应该有一个类型说明符。它与作为初始化程序没有任何关系,所以在 imo 中,它看起来像是某种空块范围。
  • 听起来像一个clang bug。这转到[expr.type.conv]/2 的“否则,表达式是指定类型的纯右值,其结果对象使用初始化程序直接初始化([dcl.init])。”,这对void 没有意义。
  • 它看起来像 lambda 表达式:link
  • Lamda 表达式应该是[](){} 而不是({})
  • @GManNickG No. (void) unused 通过 [expr.cast]/4.2[expr.static.cast]/6void(unused) 通过 [expr.type.conv]/2 的第一句进入 [expr.cast] (“如果初始化器是带括号的单个表达式,则类型转换表达式是等价的(在定义上,如果在含义上定义) 到相应的强制转换表达式。") 问题是({}) 不是“带括号的单个表达式”,因为{} 不是表达式。

标签: c++ gcc clang c++14 language-lawyer


【解决方案1】:

从一开始,C++ 语言中就存在向void 类型的转换以及返回void 值的可能性。提出问题的唯一部分是{} 在这种情况下的作用。

clang 的快速实验

int a({});

生成一条错误消息说

error: cannot initialize a variable of type 'int' with an rvalue of type 'void'

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

但是由于在clang中恰好是这种情况,所以void({})在clang中编译并没有什么异常。 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++ 中的统一初始化语法相冲突。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2012-03-11
  • 2017-01-09
  • 2017-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多