【发布时间】:2013-06-03 20:30:12
【问题描述】:
假设有一个std::array 被初始化。用双括号也没关系:
std::array<int, 2> x = {{0, 1}};
std::array<int, 2> x{{0, 1}};
在旧的聚合初始化中使用单大括号也是可以的,因为大括号省略会处理丢失的大括号:
std::array<int, 2> x = {0, 1};
但是,可以使用带有单括号的列表初始化吗? GCC 接受它,Clang 以“在使用直接列表初始化时不能省略子对象初始化周围的大括号”来拒绝它。
std::array<int, 2> x{0, 1};
标准中唯一提到大括号省略的部分是 8.5.1/12,它说:
在使用赋值表达式初始化聚合成员时,会考虑所有隐式类型转换(第 4 条)。如果赋值表达式可以初始化成员,则初始化该成员。否则,如果成员本身是子聚合,则假定大括号省略,并考虑使用赋值表达式来初始化子聚合的第一个成员。
8.5.1 是关于聚合初始化的,所以这应该意味着 Clang 拒绝是正确的,对吧?没那么快。 8.5.4/3 说:
类型 T 的对象或引用的列表初始化定义如下:
[…]
——否则,如果 T 是一个聚合,则执行聚合初始化 (8.5.1)。
我认为这意味着与聚合初始化完全相同的规则,包括大括号省略、应用,这意味着 GCC 可以正确接受。
我承认,措辞不是特别清楚。那么,哪个编译器在处理第三个 sn-p 时是正确的?大括号省略是否发生在列表初始化中,还是没有?
【问题讨论】:
-
好问题!可能值得一提的是您使用的是哪种标准。 C++11 标准,或者如果不是,哪个特定草案。
-
“类赋值初始化”称为复制初始化。它调用复制构造函数,而不是赋值运算符。
-
@TemplateRex:这就是我使用“喜欢”作品的原因。
-
@juanchopanza: n3290,与标准 IIRC 相同。
-
最好使用标准术语,人们会感到困惑,可能会认为您不理解并进行这样的对话:-)
标签: c++ c++11 language-lawyer list-initialization aggregate-initialization