Nested aggregate initialization of std::array

aggregate-initialization, arrays, c++, c++14, initialization

Solution

The braces in aggregate initialisation are largely optional, so you can write:

S c_arr[] = {1, 2, 3, 4};  // OK
std::array<S, 2> std_arr = {1, 2, 3, 4};  // OK

If you do add braces, though, then the braces are taken to apply to the next sub-object. Unfortunately, when you start nesting, this leads to silly code being valid, and sensible code like yours being invalid.

std::array<S, 2> std_arr = {{1, 2, 3, 4}};  // OK
std::array<S, 2> std_arr = {1, 2, {3, 4}};  // OK
std::array<S, 2> std_arr = {1, {2}, {3, 4}};  // OK

These are all okay. `{1, 2, 3, 4}` is a valid initialiser for the `S[2]` member of `std_arr`. `{2}` is okay because it is an attempt to initialise an `int`, and `{2}` is a valid initialiser for that. `{3, 4}` is taken as an initialiser for `S`, and it's also valid for that.

std::array<S, 2> std_arr = {{1, 2}, {3, 4}};  // error

This is not okay because `{1, 2}` is taken as a valid initialiser for the `S[2]` member. The remaining `int` sub-objects are initialised to zero.

You then have `{3, 4}`, but there are no more members to initialise.

As pointed out in the comments,

std::array<S, 2> std_arr = {{{1, 2}, {3, 4}}};

also works. The nested `{{1, 2}, {3, 4}}` is an initialiser for the `S[2]` member. The `{1, 2}` is an initialiser for the first `S` element. The `{3, 4}` is an initialiser for the second `S` element.

I'm assuming here that `std::array<S, 2>` contains an array member of type `S[2]`, which it does on current implementations, and which I believe is likely to become guaranteed, but which has been covered on SO before and is not currently guaranteed.

Problem

I wonder, why declaration of `std_arr` in the following code generates an error, while `c_arr` compiles well: ``` struct S { int a, b; }; S c_arr[] = {{1, 2}, {3, 4}}; // OK std::array<S, 2> std_arr = {{1, 2}, {3, 4}}; // Error: too many initializers ``` Both `std::array` and `S` are aggregates. From aggregate initialization on cppreference.com: If the initializer clause is a nested braced-init-list (which is not an expression and has no type), the corresponding class member is itself an aggregate: aggregate initialization is recursive. Why this initialization of `std::array` does not compile?

Original source

Related problems