Consider the following program where we create a std::array for struct element type:

struct Point
{
    int x{};
    int y{};
};
 
std::array items{
    Point{1, 2},
    Point{3, 2},
};

It works perfectly and creates a std::array with two Point elements.

Now, if we try to omit the explicit mention of Point in the initialization values as following:

std::array<Point, 2> values{
    {1, 2},
    {3, 2},
};

We should expect the array to be created. When we compile the program, compiler would raise error of too many values in initializers list.

Why is that?

Let’s go a bit in the details of std::array on how it is designed. It is a template struct aggregate with a C-style array as member.

template <typename T, std::size_t S>
struct array
{
    T implementation_defined_name[S];
}

So, in the above initialization, compiler interprets first value {1, 2} as value for implementation_defined_name array and it initializes this array with {1, 2}. Now, the compiler would find one more initializer value {3, 2} and there is no more data member in struct array to initialize this value to. So, the compiler would raise too many values error.

We can solve this by putting double braces in initializer list as shown below:

std::array<Point, 2> values{{
    {1, 2},
    {1, 2},
}};

What this will do is, it will make a single initializer value for the array data member of struct array.

Brace elision

So, we need to do this when we are not specifying explicit name for the class type or any other complex type in the initializer list for std::array. This is the issue with aggregate initialization.

We can also use double braces for fundamental types or with class types with explicit name but compiler would ignore them. This is called brace elision.

References

  1. https://www.learncpp.com/cpp-tutorial/stdarray-of-class-types-and-brace-elision/