9 Declarations [dcl]

9.5 Initializers [dcl.init]

9.5.2 Aggregates [dcl.init.aggr]

An aggregate is an array or a class ([class]) with
[Note 1: 
Aggregate initialization does not allow accessing protected and private base class' members, including constructors.
— end note]
The elements of an aggregate are:
  • for an array, the array elements in increasing subscript order, or
  • 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.
When an aggregate is initialized by an initializer list as specified in [dcl.init.list], the elements of the initializer list are taken as initializers for the elements of the aggregate.
The explicitly initialized elements of the aggregate are determined as follows:
  • If the initializer list is a brace-enclosed designated-initializer-list, the aggregate shall be of class type, the identifier in each designator shall name a direct non-static data member of the class, and the explicitly initialized elements of the aggregate are the elements that are, or contain, those members.
  • If the initializer list is a brace-enclosed initializer-list, the explicitly initialized elements of the aggregate are those for which an element of the initializer list appertains to the aggregate element or to a subobject thereof (see below).
  • Otherwise, the initializer list must be {}, and there are no explicitly initialized elements.
For each explicitly initialized element:
  • If the element is an anonymous union member and the initializer list is a brace-enclosed designated-initializer-list, the element is initialized by the braced-init-list { D }, where D is the designated-initializer-clause naming a member of the anonymous union member.
    There shall be only one such designated-initializer-clause.
    [Example 1: 
    struct C { union { int a; const char* p; }; int x; } c = { .a = 1, .x = 3 }; initializes c.a with 1 and c.x with 3.
    — end example]
  • Otherwise, if the initializer list is a brace-enclosed designated-initializer-list, the element is initialized with the brace-or-equal-initializer of the corresponding designated-initializer-clause.
    If that initializer is of the form = assignment-expression and a narrowing conversion ([dcl.init.list]) is required to convert the expression, the program is ill-formed.
    [Note 2: 
    The form of the initializer determines whether copy-initialization or direct-initialization is performed.
    — end note]
  • Otherwise, the initializer list is a brace-enclosed initializer-list.
    If an initializer-clause appertains to the aggregate element, then the aggregate element is copy-initialized from the initializer-clause.
    Otherwise, the aggregate element is copy-initialized from a brace-enclosed initializer-list consisting of all of the initializer-clauses that appertain to subobjects of the aggregate element, in the order of appearance.
    [Note 3: 
    If an initializer is itself an initializer list, the element is list-initialized, which will result in a recursive application of the rules in this subclause if the element is an aggregate.
    — end note]
    [Example 2: 
    struct A { int x; struct B { int i; int j; } b; } a = { 1, { 2, 3 } }; initializes a.x with 1, a.b.i with 2, a.b.j with 3.
    struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1{{1, 2}, {}, 4}; derived d2{{}, {}, 4}; initializes d1.b1 with 1, d1.b2 with 2, d1.b3 with 42, d1.d with 4, and d2.b1 with 0, d2.b2 with 42, d2.b3 with 42, d2.d with 4.
    — end example]
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
  • If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
  • Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
  • Otherwise, the program is ill-formed.
If the aggregate is a union and the initializer list is empty, then
  • if any variant member has a default member initializer, that member is initialized from its default member initializer;
  • otherwise, the first member of the union (if any) is copy-initialized from an empty initializer list.
[Example 3: 
struct S { int a; const char* b; int c; int d = b[a]; }; S ss = { 1, "asdf" }; initializes ss.a with 1, ss.b with "asdf", ss.c with the value of an expression of the form int{} (that is, 0), and ss.d with the value of ss.b[ss.a] (that is, 's').
struct A { string a; int b = 42; int c = -1; };
A{.c=21} has the following steps:
  • Initialize a with {}
  • Initialize b with = 42
  • Initialize c with = 21
— end example]
The initializations of the elements of the aggregate are evaluated in the element order.
That is, all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.
An aggregate that is a class can also be initialized with a single expression not enclosed in braces, as described in [dcl.init].
The destructor for each element of class type other than an anonymous union member is potentially invoked ([class.dtor]) from the context where the aggregate initialization occurs.
[Note 4: 
This provision ensures that destructors can be called for fully-constructed subobjects in case an exception is thrown ([except.ctor]).
— end note]
The number of elements ([dcl.array]) in an array of unknown bound initialized with a brace-enclosed initializer-list is the number of explicitly initialized elements of the array.
[Example 4: 
int x[] = { 1, 3, 5 }; declares and initializes x as a one-dimensional array that has three elements since no size was specified and there are three initializers.
— end example]
[Example 5: 
In struct X { int i, j, k; }; X a[] = { 1, 2, 3, 4, 5, 6 }; X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; a and b have the same value.
— end example]
An array of unknown bound shall not be initialized with an empty braced-init-list {}.73
[Note 5: 
A default member initializer does not determine the bound for a member array of unknown bound.
Since the default member initializer is ignored if a suitable mem-initializer is present ([class.base.init]), the default member initializer is not considered to initialize the array of unknown bound.
[Example 6: struct S { int y[] = { 0 }; // error: non-static data member of incomplete type }; — end example]
— end note]
[Note 6: 
Static data members, non-static data members of anonymous union members, and unnamed bit-fields are not considered elements of the aggregate.
[Example 7: struct A { int i; static int s; int j; int :17; int k; } a = { 1, 2, 3 };
Here, the second initializer 2 initializes a.j and not the static data member A​::​s, and the third initializer 3 initializes a.k and not the unnamed bit-field before it.
— end example]
— end note]
If a member has a default member initializer and a potentially-evaluated subexpression thereof is an aggregate initialization that would use that default member initializer, the program is ill-formed.
[Example 8: struct A; extern A a; struct A { const A& a1 { A{a,a} }; // OK const A& a2 { A{} }; // error }; A a{a,a