On Saturday, 30 May 2015 13:10:02 UTC+3, Piet wrote:
> Why a twodimensional array can be initialised this way:
> array<array<int, 3>, 2> matrix {1, 2, 3, 4, 5, 6};
>
> but not this way:
> array<array<int, 3>, 2> matrix {{1, 2, 3}, {4, 5, 6}};
>
> clang 3.6 says:
> error: excess elements in struct initializer
> array<array<int, 3>, 2> matrix {{1, 2, 3}, {4, 5, 6}};
> ^~~~~~~~~
> But c++-standard says in 23.3.2.1
> An array is an aggregate (8.5.1) that can be initialized with the syntax
> array<T, N> a = { initializer-list };
> where initializer-list is a comma-separated list of up to N elements whose types are convertible to T.
> I think this is ok, and array<int, 3> arr {1, 2, 3}; indeed works perfectly.
'std::array' is aggregate class that contains one and only one
non-static member that is raw array. However 23.3.2 does not say it out
but instead describes some dim things. We can initialize actual
'std::array' like that:
std::array<int, 3> arr {{1, 2, 3}};
C++11 tried to add uniform initialization mixing of
'std::initializer_list' and (not fully) backward compatible C aggregate
initialization and C++03 direct initialization (and IMO failed miserably).
For 'std::array' (that is aggregate) that allows us to omit the
innermost braces and so such syntax is valid:
std::array<int, 3> arr {1, 2, 3};
If you now nest two 'std::array's then the compiler has some idea of
what braces you may omit and what you may not omit ... but you likely
are confused and omit wrong ones. I may be also confused but mine
interpretation of it is that:
// full braces should certainly work
// I myself prefer it
std::array<std::array<int, 3>, 2> matrix_full {{{{1, 2, 3}, {4, 5, 6}}}};
// omitting innermost braces should also work
std::array<std::array<int, 3>, 2> matrix_noinner {{{1, 2, 3}, {4, 5, 6}}};
// omitting two levels of inner braces should work
std::array<std::array<int, 3>, 2> matrix_no2inner {{1, 2, 3, 4, 5, 6}};
// omitting all inner braces should work
std::array<std::array<int, 3>, 2> matrix_none {1, 2, 3, 4, 5, 6};
Above seems to work with implementations in practice. What you did
however was what compilers do not expect:
// ERROR: compiler does not understand it
array<array<int, 3>, 2> matrix {{1, 2, 3}, {4, 5, 6}};
> With vector, there is not such a problem:
> vector<vector<int> > matrix {{1, 2, 3}, {4, 5, 6}};
> works perfectly, too.
'std::vector' is not aggregate. There are no aggregate initialization of
it possible. So it has to pick from its 7 constructors (one of what is
template) to produce an object and so there are ways to confuse with it
as well. Concrete case is lucky, it picks the constructor with
'std::initializer_list' and you and compiler understand the code above
in same way.
> Why does this kind of initialization not work with array? Do I
> misunderstand the standard document?
You can often not interpret C++ standard about some single thing
without finding at least 6 relevant quotes about the issue from
different parts of over 1000 pages of it. Initialization is especially
screwed up IMO in that respect.
'std::array' is quite simple and efficient class. Genius trick to get
rid of most need for raw array. Its description in standard is
unfortunately somewhat too broad and so it is misleading.