在std :: array初始化中使用Brace elision
假设有一个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,它说:
使用赋值expression式初始化聚合成员时,将考虑所有隐式types转换(第4章)。 如果赋值expression式可以初始化一个成员,则该成员被初始化。 否则,如果该成员本身是一个子集合,则假定支撑精确,并且为该子集合的第一个成员的初始化考虑赋值expression式。
8.5.1是关于具体的聚合初始化的,所以应该表示铿锵拒绝是正确的吧? 没那么快 8.5.4 / 3说:
Ttypes的对象或引用的列表初始化定义如下:
[…]
– 否则,如果T是聚合,则执行聚合初始化(8.5.1)。
我认为这意味着与汇总初始化(包括大括号)一样的规则也适用,这意味着GCC是正确的接受。
我承认,措辞不是特别清楚。 那么,哪个编译器对待第三个片段是正确的呢? 大括号是否在列表初始化中发生,或者不是?
Brace elision适用,但不适用于C ++ 11。 在C ++ 14中,它们将因为http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270而适用。; 如果你幸运的话,Clang会将其移植到他们的C ++ 11模式(希望他们会!)。
相关: http : //en.cppreference.com/w/cpp/language/aggregate_initialization
简而言之,
struct S { int x; struct Foo { int i; int j; int a[3]; } b; }; S s1 = { 1, { 2, 3, {4, 5, 6} } }; S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax S s4{1, 2, 3, 4, 5, 6}; // error in C++11: brace-elision only allowed with equals sign // okay in C++14