找到你要的答案

Q:Brace elision in std::array initialization

Q:括号省略在std::数组初始化

Suppose there's an std::array to be initialized. It's okay if using double braces:

std::array<int, 2> x = {{0, 1}};
std::array<int, 2> x{{0, 1}};

It's also okay to use single braces in the good old aggregate initialization, as the brace elision will take care of the missing braces:

std::array<int, 2> x = {0, 1};

However, is it okay to use list-initialization with single braces? GCC accepts it, Clang rejects it with "cannot omit braces around initialization of subobject when using direct list-initialization".

std::array<int, 2> x{0, 1};

The only part of the standard where brace elision is mentioned is 8.5.1/12, which says:

All implicit type conversions (Clause 4) are considered when initializing the aggregate member with an assignment-expression. If the assignment-expression can initialize a member, the member is initialized. Otherwise, if the member is itself a subaggregate, brace elision is assumed and the assignment-expression is considered for the initialization of the first member of the subaggregate.

8.5.1 is about aggregate initialization specifically, so that should mean Clang is correct to reject, right? Not so fast. 8.5.4/3 says:

List-initialization of an object or reference of type T is defined as follows:

[…]

— Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1).

I thinks it means that the exact same rules as with aggregate initialization, including brace elision, apply, meaning GCC is correct to accept.

I admit, the wording is not particularly clear. So, which compiler is right in its treatment of the third snippet? Does the brace elision happen in list-initialization, or it doesn't?

假设有一个STD::数组初始化。使用双支撑没关系:

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是一个集合,进行聚合初始化(8.5.1)。

我认为这意味着同样的规则与集合初始化,包括括号省略,适用,意义GCC是正确的接受。

我承认,措辞不是特别清楚。因此,编译器就在其第三段处理?并支撑省略列表初始化发生,或不?

answer1: 回答1:

Brace elision applies, but not in C++11. In C++14, they will apply because of http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270 . If you are lucky, Clang will backport that to their C++11 mode (let's hope they will!).

括号省略适用,但不是C++ 11。在C++ 14,他们将因为HTTP:/ / www.open-std.org / JTC1第22分技术委员会/ C++程序设计语言工作组/文档/ cwg_defects HTML # 1270。如果你幸运的话,Clang将通过对C++ 11模式(希望他们能!)。

answer2: 回答2:

Relevant: http://en.cppreference.com/w/cpp/language/aggregate_initialization

In short,

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

相关: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
c++  c++11  language-lawyer  brace-initialization  aggregate-initialization