简体   繁体   中英

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

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.

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}} }};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM