How do I initialize an object of std::array<std::array<T, 2>, 2>?
Asked Answered
T

1

5

I'm trying to initialize objects of type thing:

template<typename T>
  struct thing : std::array<std::array<T, 2>, 2>
  {
  };

thing<int> t1 {{ {1,2}, {3,4} }};

I get:

 error: no matching function for call to ‘thing<int>::thing(<brace-enclosed initializer list>)’
 thing<int> t1 {{{1,2},{3,4}}};

Ditto with

thing<int> t0{{ 1, 2, 3, 4 }};

and several other things.

Toxicogenic answered 25/7, 2014 at 14:30 Comment(2)
why are you tying to inherit from a 2D array?Lailaibach
If you're trying to alias the array, you'd better do template <class T> using thing = std::array<T, 2>, 2>;Bucket
I
9

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}} }};
Ingoing answered 25/7, 2014 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.