47

假设有一个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 可以正确接受。

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

4

2 回答 2

23

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

于 2013-06-07T21:12:09.747 回答
8

相关: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
于 2015-03-05T23:54:39.743 回答