std :: array初始化中的brace elision

时间:2013-06-07 13:45:53

标签: c++ c++11 language-lawyer list-initialization aggregate-initialization

假设要初始化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接受是正确的。

我承认,措辞不是特别清楚。那么,哪个编译器正确处理第三个片段呢?括号省略是否在列表初始化中发生,或者不是?

2 个答案:

答案 0 :(得分:22)

Brace elision适用,但不适用于C ++ 11。在C ++ 14中,由于http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270,它们将适用。如果你很幸运,Clang会将其反向移植到他们的C ++ 11模式(我们希望他们会这样做!)。

答案 1 :(得分:5)

相关: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