If you're using a C++17 compiler, you're only missing an extra set of braces. The following compiles:
thing<int> t1 { { { {1,2}, {3,4} } } };
// | | | |- braces for inner array
// | | |--- braces for outer array
// | |----- braces for base sub object of thing
// |------- braces for list initialization of thing
C++17 modified the rules for aggregates to allow base classes, as long as they're public
and non-virtual
.
From §11.6.1/1 [dcl.init.aggr]
An aggregate is an array or a class with
(1.1)
no user-provided, explicit
, or inherited constructors ([class.ctor]),
(1.2)
no private or protected non-static data members ([class.access]),
(1.3)
no virtual functions, and
(1.4)
no virtual, private, or protected base classes ([class.mi]).
The base classes are now considered elements of the aggregate, and can themselves be initialized using list-initialization.
The elements of an aggregate are:
(2.1)
for an array, the array elements in increasing subscript order, or
(2.2)
for a class, the direct base classes in declaration order, followed by the direct non-static data members ([class.mem]) that are not members of an anonymous union, in declaration order.
C++14, and earlier, version of the answer follows:
std::array
is an aggregate, and the initialization done using a braced-init-list is aggregate initialization. However, thing
is not an aggregate because it has a base class.
From §8.5.1/1 [dcl.init.aggr]
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Thus, aggregate initialization is not going to work. Depending on what you're attempting to do, you either want to provide a constructor for thing
that takes an std::array<std::array<T, 2>, 2>
argument, and initialize the base subobject
template<typename T>
struct thing : std::array<std::array<T, 2>, 2>
{
thing(std::array<std::array<T, 2>, 2> arr)
: std::array<std::array<T, 2>, 2>(arr)
{}
};
thing<int> t{ {{ {{1,2}}, {{3,4}} }} };
Or have thing
contain the std::array
as a data member. Now thing
is still an aggregate.
template<typename T>
struct thing
{
std::array<std::array<T, 2>, 2> arr;
};
thing<int> t{ {{ {{1,2}}, {{3,4}} }} };
If what you're attempting to do is have thing
be an alias for an array<array<T,2>,2>
, then you don't need either of the above. Use
template<typename T>
using thing = std::array<std::array<T, 2>, 2>;
thing<int> t{{ {{1,2}}, {{3,4}} }};
template <class T> using thing = std::array<T, 2>, 2>;
– Bucket