Search code examples
c++initializationstdarraylist-initialization

List initialisation of two dimensional std::array


In the following program, I tried to initialise my 2x2-element std::array using the line which has nested list initialisation (currently commented out). MSVC2017 gave me a compiler error with "too many initializers". Why?

I then gave the non-nested list initialisation a go which worked. Why?

This appears to be inconsistent with initialisation of a nested std::vector. See third line of main(). What is going on here please?

#include <array>
#include <iostream>
#include <vector>

int main()
{
    //std::array<std::array<int,2>,2> x = {{0,1},{2,3}};    // ERROR: TOO MANY INITIALIZERS
    std::array<std::array<int,2>,2> x = {0,1,2,3};          // OK
    std::vector<std::vector<int>> y = {{0,1},{2,3}};        // ALSO OK: NOT TOO MANY INITIALIZERS IF A std::vector?
}

Solution

  • In this declaration

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

    you have three nested aggregates. The first pair of values enclosed in braces

    {0,1}
    

    is considered by the compiler as an initializer of the second aggregate that is present in the declaration as one sub-aggregate. So the second pair of values in braces

    {2,3}
    

    are considered by the compiler as redundant that has no corresponding object.

    You could declare the array for example like

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

    The braces may be elided when an aggregate is initialized. (C++17 Standard, 11.6.1 Aggregates)

    12 Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the elements of a subaggregate; it is erroneous for there to be more initializer-clauses than elements. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the elements of the subaggregate; any remaining initializer-clauses are left to initialize the next element of the aggregate of which the current subaggregate is an element.

    So in this declaration

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

    the braces are elided and the aggregate is initialized as it is described in the quote..

    In this declaration

    std::vector<std::vector<int>> y = {{0,1},{2,3}};
    

    there is used the constructor of the class std::vector that accepts std::initializer_list as an argument. In this case the constructor builds as many elements of the vector as there are elements in the initializer list.