An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
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 members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause. If the initializer-clause is an expression and a narrowing conversion ([dcl.init.list]) is required to convert the expression, the program is ill-formed. [ Note: If an initializer-clause is itself an initializer list, the member is list-initialized, which will result in a recursive application of the rules in this section if the member is an aggregate. — end note ] [ Example:
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. — end example ]
An aggregate that is a class can also be initialized with a single expression not enclosed in braces, as described in [dcl.init].
An array of unknown size initialized with a brace-enclosed initializer-list containing n initializer-clauses, where n shall be greater than zero, is defined as having n elements ([dcl.array]). [ Example:
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 ] An empty initializer list {} shall not be used as the initializer-clause for an array of unknown bound.106
Static data members and anonymous bit-fields are not considered members of the class for purposes of aggregate initialization. [ Example:
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 anonymous bit-field before it. — end example ]
An initializer-list is ill-formed if the number of initializer-clauses exceeds the number of members or elements to initialize. [ Example:
char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error
is ill-formed. — end example ]
If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from its brace-or-equal-initializer or, if there is no brace-or-equal-initializer, from an empty initializer list ([dcl.init.list]). [ Example:
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'), and in
struct X { int i, j, k = 42; }; 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 ]
If an aggregate class C contains a subaggregate member m that has no members for purposes of aggregate initialization, the initializer-clause for m shall not be omitted from an initializer-list for an object of type C unless the initializer-clauses for all members of C following m are also omitted. [ Example:
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 ]
If an incomplete or empty initializer-list leaves a member of reference type uninitialized, the program is ill-formed.
When initializing a multi-dimensional array, the initializer-clauses initialize the elements with the last (rightmost) index of the array varying the fastest ([dcl.array]). [ Example:
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 ]
Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the members of a subaggregate; it is erroneous for there to be more initializer-clauses than members. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the members of the subaggregate; any remaining initializer-clauses are left to initialize the next member of the aggregate of which the current subaggregate is a member. [ Example:
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 ]
All implicit type conversions (Clause [conv]) are considered when initializing the aggregate member with an assignment-expression. If the assignment-expression can initialize a member, the member is initialized. Otherwise, if the member is itself a subaggregate, brace elision is assumed and the assignment-expression is considered for the initialization of the first member of the subaggregate. [ Note: As specified above, brace elision cannot apply to subaggregates with no members for purposes of aggregate initialization; an initializer-clause for the entire subobject is required. — end note ]
[ Example:
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: An aggregate array or an aggregate class may contain members of a class type with a user-provided constructor ([class.ctor]). Initialization of these aggregate objects is described in [class.expl.init]. — end note ]
[ Note: Whether the initialization of aggregates with static storage duration is static or dynamic is specified in [basic.start.init] and [stmt.dcl]. — end note ]
When a union is initialized with a brace-enclosed initializer, the braces shall only contain an initializer-clause for the first non-static data member of the union. [ Example:
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
— end example ]
[ Note: 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 initializer-lists, but nonetheless C++ does not have zero length arrays.