9 Declarations [dcl.dcl]

9.4 Initializers [dcl.init]

9.4.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 or 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 {}.81
[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}; // OK struct B { int n = B{}.n; // error }; — end example]
When initializing a multidimensional array, the initializer-clauses initialize the elements with the last (rightmost) index of the array varying the fastest ([dcl.array]).
[Example 9: 
int x[2][2] = { 3, 1, 4, 2 }; initializes x[0][0] to 3, x[0][1] to 1, x[1][0] to 4, and x[1][1] to 2.
On the other hand, float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; initializes the first column of y (regarded as a two-dimensional array) and leaves the rest zero.
— end example]
Each initializer-clause in a brace-enclosed initializer-list is said to appertain to an element of the aggregate being initialized or to an element of one of its subaggregates.
Considering the sequence of initializer-clauses, and the sequence of aggregate elements initially formed as the sequence of elements of the aggregate being initialized and potentially modified as described below, each initializer-clause appertains to the corresponding aggregate element if
  • the aggregate element is not an aggregate, or
  • the initializer-clause begins with a left brace, or
  • the initializer-clause is an expression and an implicit conversion sequence can be formed that converts the expression to the type of the aggregate element, or
  • the aggregate element is an aggregate that itself has no aggregate elements.
Otherwise, the aggregate element is an aggregate and that subaggregate is replaced in the list of aggregate elements by the sequence of its own aggregate elements, and the appertainment analysis resumes with the first such element and the same initializer-clause.
[Note 7: 
These rules apply recursively to the aggregate's subaggregates.
[Example 10: 
In struct S1 { int a, b; }; struct S2 { S1 s, t; }; S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; S2 y[2] = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; x and y have the same value.
— end example]
— end note]
This process continues until all initializer-clauses have been exhausted.
If any initializer-clause remains that does not appertain to an element of the aggregate or one of its subaggregates, the program is ill-formed.
[Example 11: char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error: too many initializers — end example]
[Example 12: 
float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, }; is a completely-braced initialization: 1, 3, and 5 initialize the first row of the array y[0], namely y[0][0], y[0][1], and y[0][2].
Likewise the next two lines initialize y[1] and y[2].
The initializer ends early and therefore y[3]'s elements are initialized as if explicitly initialized with an expression of the form float(), that is, are initialized with 0.0.
In the following example, braces in the initializer-list are elided; however the initializer-list has the same effect as the completely-braced initializer-list of the above example, float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
The initializer for y begins with a left brace, but the one for y[0] does not, therefore three elements from the list are used.
Likewise the next three are taken successively for y[1] and y[2].
— end example]
[Note 8: 
The initializer for an empty subaggregate is needed if any initializers are provided for subsequent elements.
[Example 13: struct S { } s; struct A { S s1; int i1; S s2; int i2; S s3; int i3; } a = { { }, // Required initialization 0, s, // Required initialization 0 }; // Initialization not required for A​::​s3 because A​::​i3 is also not initialized — end example]
— end note]
[Example 14: struct A { int i; operator int(); }; struct B { A a1, a2; int z; }; A a; B b = { 4, a, a };
Braces are elided around the initializer-clause for b.a1.i.
b.a1.i is initialized with 4, b.a2 is initialized with a, b.z is initialized with whatever a.operator int() returns.
— end example]
[Note 9: 
An aggregate array or an aggregate class can contain elements of a class type with a user-declared constructor ([class.ctor]).
Initialization of these aggregate objects is described in [class.expl.init].
— end note]
[Note 10: 
Whether the initialization of aggregates with static storage duration is static or dynamic is specified in [basic.start.static], [basic.start.dynamic], and [stmt.dcl].
— end note]
When a union is initialized with an initializer list, there shall not be more than one explicitly initialized element.
[Example 15: union u { int a; const char* b; }; u a = { 1 }; u b = a; u c = 1; // error u d = { 0, "asdf" }; // error u e = { "asdf" }; // error u f = { .b = "asdf" }; u g = { .a = 1, .b = "asdf" }; // error — end example]
[Note 11: 
As described above, the braces around the initializer-clause for a union member can be omitted if the union is a member of another aggregate.
— end note]
The syntax provides for empty braced-init-lists, but nonetheless C++ does not have zero length arrays.