Initializing array elements of user-defined types

g ++ 4.7 supports the initialization of an array member, and I started playing with it.

The code below does not compile.

struct A { A(int){}; A(const A&) = delete; A& operator=(const A&) = delete; ~A(){}; }; struct B { B(): a{{0},{1}} {}; A a[2]; }; B b; 

Error message with gcc 4.8 (preerelease):

 n.cc: In constructor 'B::B()': n.cc:12:20: error: use of deleted function 'A::A(const A&)' a{{0},{1}} ^ n.cc:4:8: error: declared here A(const A&) = delete; ^ 

Is there any way to make this code work? I can't easily change the constructors, destructor A. It seems I need a move constructor or a copy constructor to initialize the array, but this seems to contradict intuition, since all I really need is to build in place.

It works if I split [2] into 2 members a0 and a1 and create them separately. However, this looks suspicious.

+6
source share
2 answers

Arrays are aggregates, and aggregate initialization always uses copy initialization. C ++ 11 ยง8.5.1 / 1:

An aggregate is an array or class without user-provided constructors, no brace-or-equal-initializer s for non-static data members, without personal or protected non-static data elements, base classes, and virtual functions.

ยง8.5.1 / 2:

When an aggregate is initialized with an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, increasing the index or order of the members. Each member is initialized with a copy from the corresponding initializer clause. & hellip;

(Emphasize mine.)

Furthermore, the compiler does not imply the creation of a move constructor if there is a constructor declared by the user (ยง12.8 / 9); because you have a user-declared copy constructor that is defined as remote, A has neither a copy nor a move constructor. Explicitly adding a move constructor works:

 struct A { A(int) { } A(A const&) = delete; A& operator = (A const&) = delete; A(A&&) = default; ~A() = default; }; struct B { B() : a{{0}, {1}} { } A a[2]; }; int main() { B b; } 

online demo

This is about the same as you want when you receive.

+2
source

Inside the initialization list (8.5.4p1) of the aggregate (8.5.1), the initialization form executed on the aggregate elements is copy initialization (8.5.1p2), even if the initialization is a direct -initialization list:

When an aggregate is initialized with a list of initializers, as specified in 8.5.4, the elements of the list of initializers are taken as initializers for members of the aggregate, increasing the index or order of members. Each element is initialized with a copy from the corresponding initializer clause.

However, just because the initialization form executed is copying does not mean that a copy is occurring. According to copy-list-initialization of non-copyable types, initialization of copy-list must be identical to initialization of direct list, except that explicit constructors are not allowed.

+4
source

All Articles