47
votes

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?

2
Nice question! It might be worth mentioning which standard you are using. The C++11 standard, or if not, which particular draft.juanchopanza
"assignment-like initialization" is called copy-initialization. It calls the copy constructor, not the assignment operator.TemplateRex
@TemplateRex: that's why I used the work "like".user784668
@juanchopanza: n3290, which is identical to the standard IIRC.user784668
it's better to use the standard terminology, people get confused and might think you didn't understand and have conversations like this one :-)TemplateRex

2 Answers

23
votes

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!).

8
votes

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