aggregate initialization

< cpp‎ | language
Revision as of 19:59, 31 May 2013 by P12bot (Talk | contribs)

C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Function declaration
Lambda function declaration
inline specifier
Exception specifications (deprecated)
noexcept specifier (C++11)
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Alternative representations
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Attributes (C++11)
typedef declaration
Type alias declaration (C++11)
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Class-specific function properties
Special member functions

Initializes an aggregate from braced-init-list



T object = {arg1, arg2, ...}; (1)
T object {arg1, arg2, ...}; (2) (since C++11)


Aggregate initialization is a form of list-initialization, which initializes aggregates

An aggregate is an object of the type that is one of the following

  • array type
  • class type (typically, struct or union), that has
  • no private or protected members
  • no user-provided constructors
  • no base classes
  • no virtual member functions
  • no brace-or-equal initializers for non-static members

The effects of aggregate initialization are:

  • Each array element or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.
  • If the initializer clause is an expression, implicit conversions are allowed, except (since C++11) if they are narrowing (as in list-initialization).
  • If the initializer clause is a nested braced-init-list, the corresponding class member is itself an aggregate: aggregate initialization is recursive.
  • If the object is an array of unknown size, and the supplied brace-enclosed initializer list has n clauses, the size of the array is n
  • Static data members and anonymous bit-fields are skipped during aggregate initialization.
  • If the number of initializer clauses exceeds the number of members to initialize, the program is ill-formed (compiler error)
  • If the number of initializer clauses is less than the number of members, the remaining members are initialized by empty lists, which performs value-initialization. If a member of a reference type is one of these remaining members, the program is ill-formed (references cannot be value-initialized)
  • If the aggregate initialization uses the form with the equal sign (T a = {args..}), the braces around the nested initializer lists may be elided (omitted), in which case, as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, and the subsequent initializer clauses are used to initialize the following members of the object. However, if the object has a sub-aggregate without any members (an empty struct, or a struct holding only static members), brace elision is not allowed, and an empty nested list {} must be used.
  • When a union is initialized by aggregate initialization, only its first non-static data members is initialized.


Until C++11, narrowing conversions were permitted in aggregate initialization, but they are no longer allowed.

Until C++11, aggregate initialization could not be used in a constructor initializer list due to syntax restrictions.


#include <string>
#include <array>
struct S {
    int x;
    struct Foo {
        int i;
        int j;
        int a[3];
    } b;
union U {
    int a;
    const char* b;
int main()
    S s1 = { 1, { 2, 3, {4, 5, 6} } };
    S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
    S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
//  S s4{1, 2, 3, 4, 5, 6}; // error: brace-elision only allowed with equals sign
    int ar[] = {1,2,3}; // ar is int[3]
//  char cr[3] = {'a', 'b', 'c', 'd'}; // too many initializer clauses
    char cr[3] = {'a'}; // array initialized as {'a', '\0', '\0'}
    int ar2d1[2][2] = {{1, 2}, {3, 4}}; // fully-braced 2D array: {1, 2}
                                        //                        {3, 4}
    int ar2d2[2][2] = {1, 2, 3, 4}; // brace elision: {1, 2}
                                    //                {3, 4}
    int ar2d3[2][2] = {{1}, {2}};   // only first column: {1, 0}
                                    //                    {2, 0}
    std::array<int, 3> std_ar2{ {1,2,3} };    // std::array is an aggregate
    std::array<int, 3> std_ar1 = {1, 2, 3}; // brace-elision okay
    int ai[] = { 1, 2.0 }; // narrowing conversion from double to int:
                           // error in C++11, okay in C++03
    std::string ars[] = {std::string("one"), // copy-initialization
                         "two",              // conversion, then copy-initialization
                         {'t', 'h', 'r', 'e', 'e'} }; // list-initialization
    U u1 = {1}; // OK, first member of the union
//    U u2 = { 0, "asdf" }; // error: too many initializers for union
//    U u3 = { "asdf" }; // error: invalid conversion to int

See also