48

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?

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Nice question! It might be worth mentioning which standard you are using. The C++11 standard, or if not, which particular draft. – juanchopanza Jun 07 '13 at 13:50
  • "assignment-like initialization" is called copy-initialization. It calls the copy constructor, not the assignment operator. – TemplateRex Jun 07 '13 at 13:52
  • @TemplateRex: that's why I used the work "like". –  Jun 07 '13 at 13:53
  • @juanchopanza: n3290, which is identical to the standard IIRC. –  Jun 07 '13 at 13:53
  • 1
    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 Jun 07 '13 at 13:54
  • @TemplateRex: the standard terminology in this case is actually aggregate initialization, if you want to be pedantic. Edited, anyway. –  Jun 07 '13 at 13:57
  • Duplicate (see [this question](http://stackoverflow.com/questions/8192185/using-stdarray-with-initialization-lists))? – maverik Jun 07 '13 at 14:01
  • @maverik: not really. I'm asking about some specific intricacies of list-initialization, not about aggregate initialization. –  Jun 07 '13 at 14:08
  • not meaning to be pedantic, just precise, because there are many questions on SO about confusion between assignment/copying. – TemplateRex Jun 07 '13 at 14:08
  • "It's okay if using double braces". I don't think that's true. The standard gives no guarantee that it works with double braces, as far as I know. – Johannes Schaub - litb Jun 07 '13 at 21:06
  • Fyi, in the C++11 edition of Stroustrup's 'The C++ programming language' he uses direct list initialization in his simplified Array example (8.2.4, page 208) - but the last word has the C++ 11 standard, of course. – maxschlepzig Mar 08 '14 at 21:52

2 Answers2

24

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

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • As of now, `clang-5.0` in the archlinux still does not support brace elision even with `-std=c++17`. – VP. Oct 01 '17 at 12:43
10

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
kchoi
  • 473
  • 1
  • 4
  • 11