std::array
is designed to be an aggregate. It has no user-provided constructors, so one can initialize it using aggregate initialization. Because your Array
class has a private base class, it is not an aggregate, and can only be initialized by a constructor.
Another way of looking at it is that since Array
has members that are hidden from the user, it does not make sense for the language to allow the user to directly initialize those elements using the aggregate syntax, the way one might initialize a normal array. Instead the user must call a constructor, wherein the Array
class's author has explicitly implemented the necessary initialization logic to fulfill the Array
class's contract.
One simple solution is to make the std::array
base class public. If you don't want to do that, you can write your own initializer_list
constructor, but it's tricky and imperfect:
// delegate to a helper constructor
Array(std::initializer_list<T> il) : Array(il, std::make_index_sequence<N>{}) {}
private:
template <size_t... i>
Array(std::initializer_list<T> il, std::index_sequence<i...>)
: std::array<T, N>{(i < il.size() ? il.begin()[i] : T{})...} {}
The helper constructor uses an element from the initializer list to initialize the corresponding std::array
element, if one exists; otherwise, it initializes it from T{}
.
The main problem with this is that if T
is a class that cannot be value-initialized, then this Array
constructor cannot be called even if N
initializers are supplied, because the compiler cannot enforce the "il
contains N
elements" condition at compile time, and thus must assume that T{}
may be called at runtime. There is no way to perfectly emulate aggregate initialization.