# List-initialization (since C++11)

From cppreference.com
< cpp‎ | language

Initializes an object from braced-init-list.

### Syntax

#### Direct-list-initialization

T object `{` arg1, arg2, ... `};`
T object`{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `};` | (since C++20)
| (1) |
T `{` arg1, arg2, ... `}`
T `{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}` | (since C++20)
| (2) |
`new` T `{` arg1, arg2, ... `}`
`new` T `{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}` | (since C++20)
| (3) |
Class `{` T member `{` arg1, arg2, ... `}; };`
Class `{` T member `{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}; };` | (since C++20)
| (4) |
Class`::`Class`() :` member `{` arg1, arg2, ... `} {...`
Class`::`Class`() :` member `{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ...`} {...` | (since C++20)
| (5) |

#### Copy-list-initialization

T object `= {` arg1, arg2, ... `};`
T object `= {.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `};` | (since C++20)
| (6) |
function `({` arg1, arg2, ... `})`
function `({.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `})` | (since C++20)
| (7) |
`return {` arg1, arg2, ... `};`
`return` `{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `};` | (since C++20)
| (8) |
object `[{` arg1, arg2, ... `}]`
object `[{.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}]` | (since C++20)
| (9) |
object `= {` arg1, arg2, ... `}`
object `= {.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}` | (since C++20)
| (10) |
U `({` arg1, arg2, ... `})`
U `({.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `})` | (since C++20)
| (11) |
Class `{` T member `= {` arg1, arg2, ... `}; };`
Class `{` T member `= {.`des1 `=` arg1 `, .`des2 `{` arg2 `}` ... `}; };` | (since C++20)
| (12) |

List initialization is performed in the following situations:

- direct-list-initialization (both explicit and non-explicit constructors are considered)

1) initialization of a named variable with a braced-init-list (that is, a possibly empty brace-enclosed list of expressions or nested braced-init-lists)
2) initialization of an unnamed temporary with a braced-init-list
3) initialization of an object with dynamic storage duration with a new-expression, where the initializer is a braced-init-list
4) in a non-static data member initializer that does not use the equals sign
5) in a member initializer list of a constructor if braced-init-list is used

- copy-list-initialization (both explicit and non-explicit constructors are considered, but only non-explicit constructors may be called)

6) initialization of a named variable with a braced-init-list after an equals sign
7) in a function call expression, with braced-init-list used as an argument and list-initialization initializes the function parameter
8) in a return statement with braced-init-list used as the return expression and list-initialization initializes the returned object
9) in a subscript expression with a user-defined `operator[]`, where list-initialization initializes the parameter of the overloaded operator
10) in an assignment expression, where list-initialization initializes the parameter of the overloaded operator
11) functional cast expression or other constructor invocations, where braced-init-list is used in place of a constructor argument. Copy-list-initialization initializes the constructor's parameter (note; the type U in this example is not the type that's being list-initialized; U's constructor's parameter is)
12) in a non-static data member initializer that uses the equals sign

### Explanation

The effects of list-initialization of an object of type `T` are:

If the braced-init-list contains a designated-initializer-list, `T` shall be an aggregate class. The ordered identifiers in the designators of the designated-initializer-list shall form a subsequence of the ordered identifiers in the direct non-static data members of `T`. Aggregate initialization is performed. | (since C++20)

- If `T` is an aggregate class and the braced-init-list has a single element of the same or derived type (possibly cv-qualified), the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).
- Otherwise, if `T` is a character array and the braced-init-list has a single element that is an appropriately-typed string literal, the array is initialized from the string literal as usual.

- Otherwise, if `T` is an aggregate type, aggregate initialization is performed.

- Otherwise, if the braced-init-list is empty and `T` is a class type with a default constructor, value-initialization is performed.

- Otherwise, if `T` is a specialization of std::initializer_list, the `T` object is direct-initialized or copy-initialized, depending on context, from a prvalue of the same type initialized from (until C++17) the braced-init-list.

- Otherwise, the constructors of `T` are considered, in two phases:

  - All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list

  - If the previous stage does not produce a match, all constructors of `T` participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all).

Otherwise, if： `T` is an enumeration type that with fixed underlying type `U` (which is int if the enumeration is scoped and its underlying type is not manually specified), and the initialization is direct-list-initialization, and the braced-init-list has only one initializer v that is implicitly convertible to `U`, and the conversion from v to `U` is non-narrowing, then the enumeration is initialized with the result of converting v to `U`. | (since C++17)

- Otherwise (if `T` is not a class type), if the braced-init-list has only one element and either `T` is not a reference type or is a reference type whose referenced type is same as or is a base class of the type of the element, `T` is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), except that narrowing conversions are not allowed.

- Otherwise, if `T` is a reference type that is not compatible with the type of the element:

a prvalue temporary of the type referenced by `T` is copy-list-initialized, and the reference is bound to that temporary (this fails if the reference is a non-const lvalue reference). | (until C++17)
a prvalue is generated. The prvalue initializes its result object by copy-list-initialization. The prvalue is then used to direct-initialize the reference (this fails if the reference is a non-const lvalue reference). The type of the temporary is the type referenced by `T`, unless `T` is “reference to array of unknown bound of `U`”, in which case the type of the temporary is the type of x in the declaration U x[] H, where `H` is the initializer list (since C++20). | (since C++17)

- Otherwise, if the braced-init-list has no elements, `T` is value-initialized.

### Narrowing conversions

List-initialization limits the allowed implicit conversions by prohibiting the following:

- conversion from a floating-point type to an integer type

conversion from a long double to double or to float and conversion from double to float, except where the source is a constant expression and overflow does not occur | (until C++23)
conversion from a floating-point type `T` to another floating-point type whose floating-point conversion rank is neither greater than nor equal to that of `T`, except where the source is a constant expression and overflow does not occur | (since C++23)

- conversion from an integer type to a floating-point type, except where the source is a constant expression whose value can be stored exactly in the target type

- conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where
  - the source is a bit-field whose width w is less than that of its type (or, for an enumeration type, its underlying type) and the target type can represent all the values of a hypothetical extended integer type with width w and with the same signedness as the original type, or
  - the source is a constant expression whose value can be stored exactly in the target type

- conversion from a pointer type or pointer-to-member type to bool

### Notes

Every initializer clause is sequenced before any initializer clause that follows it in the braced-init-list. This is in contrast with the arguments of a function call expression, which are unsequenced (until C++17)indeterminately sequenced (since C++17).

A braced-init-list is not an expression and therefore has no type, e.g. decltype({1, 2}) is ill-formed. Having no type implies that template type deduction cannot deduce a type that matches a braced-init-list, so given the declaration template<class T> void f(T); the expression f({1, 2, 3}) is ill-formed. However, the template parameter can otherwise be deduced, as is the case for std::vector<int> v(std::istream_iterator<int>(std::cin), {}), where the iterator type is deduced by the first argument but also used in the second parameter position. A special exception is made for type deduction using the keyword auto, which deduces any braced-init-list as std::initializer_list in copy-list-initialization.

Also because a braced-init-list has no type, special rules for overload resolution apply when it is used as an argument to an overloaded function call.

Aggregates copy/move initialize directly from single-element braced-init-list of the same type, but non-aggregates consider initializer_list constructors first:

    struct X {}; // aggregate

    struct Q     // non-aggregate
    {
        Q() = default;
        Q(Q const&) = default;
        Q(std::initializer_list<Q>) {}
    };

    int main()
    {
        X x;
        X x2 = X{x}; // copy-constructor (not aggregate initialization)

        Q q;
        Q q2 = Q{q}; // initializer-list constructor (not copy constructor)
    }

Some compilers (e.g., gcc 10) only consider conversion from a pointer or a pointer-to-member to bool narrowing in C++20 mode.

Feature-test macro | Value | Std | Comment
--- | --- | --- | ---
`__cpp_initializer_lists` | 200806L | (C++11) | List-initialization and std::initializer_list

### Example

Run this code

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>

    struct Foo
    {
        std::vector<int> mem = {1, 2, 3}; // list-initialization of a non-static member
        std::vector<int> mem2;

        Foo() : mem2{-1, -2, -3} {} // list-initialization of a member in constructor
    };

    std::pair<std::string, std::string> f(std::pair<std::string, std::string> p)
    {
        return {p.second, p.first}; // list-initialization in return statement
    }

    int main()
    {
        int n0{};  // value-initialization (to zero)
        int n1{1}; // direct-list-initialization

        std::string s1{'a', 'b', 'c', 'd'}; // initializer-list constructor call
        std::string s2{s1, 2, 2};           // regular constructor call
        std::string s3{0x61, 'a'}; // initializer-list ctor is preferred to (int, char)

        int n2 = {1}; // copy-list-initialization
        double d = double{1.2}; // list-initialization of a prvalue, then copy-init
        auto s4 = std::string{"HelloWorld"}; // same as above, no temporary
                                             // created since C++17

        std::map<int, std::string> m = // nested list-initialization
        {
            {1, "a"},
            {2, {'a', 'b', 'c'}},
            {3, s1}
        };

        std::cout << f({"hello", "world"}).first // list-initialization in function call
                  << '\n';

        const int (&ar)[2] = {1, 2}; // binds an lvalue reference to a temporary array
        int&& r1 = {1}; // binds an rvalue reference to a temporary int
    //  int& r2 = {2}; // error: cannot bind rvalue to a non-const lvalue ref

    //  int bad{1.0}; // error: narrowing conversion
        unsigned char uc1{10}; // okay
    //  unsigned char uc2{-1}; // error: narrowing conversion

        Foo f;

        std::cout << n0 << ' ' << n1 << ' ' << n2 << '\n'
                  << s1 << ' ' << s2 << ' ' << s3 << '\n';
        for (auto p : m)
            std::cout << p.first << ' ' << p.second << '\n';
        for (auto n : f.mem)
            std::cout << n << ' ';
        for (auto n : f.mem2)
            std::cout << n << ' ';

        [](...){}(d, ar, r1, uc1); // has effect of [[maybe_unused]]
    }

Output:

    world
    0 1 1
    abcd cd aa
    1 a
    2 abc
    3 abcd
    1 2 3 -1 -2 -3

### Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR | Applied to | Behavior as published | Correct behavior
--- | --- | --- | ---
CWG 1288 | C++11 | list-initializing a reference with a single-element braced-init-list always bound the reference to a temporary | bind to that element if valid
CWG 1324 | C++11 | initialization considered first for initialization from `{}` | aggregate initialization considered first
CWG 1467 | C++11 | same-type initialization of aggregates and character arrays was prohibited; initializer-list constructors had priority over copy constructors for single-element lists | same-type initialization allowed; single-element lists initialize directly
CWG 1494 | C++11 | when list-initializing a reference with an element of an incompatible type, it was unspecified whether the temporary created is direct-list-initialized or copy-list-initialized | it depends on the kind of initialization for the reference
CWG 2137 | C++11 | initializer-list constructors lost to copy constructors when list-initializing `X` from `{X}` | non-aggregates consider initializer-lists first
CWG 2267 | C++11 | the resolution of CWG issue 1494 made clear that temporaries could be direct-list-initialized | they are copy-list-initialized when list-initializing references
CWG 2374 | C++17 | direct-list-initialization of an enum allowed too many source types | restricted
CWG 2627 | C++11 | a narrow bit-field of a larger integer type can be promoted to a smaller integer type, but it was still a narrowing conversion | it is not a narrowing conversion
P1957R2 | C++11 | conversion from a pointer/pointer-to -member to bool was not narrowing | made narrowing

### See also

- constructor
- converting constructor
- copy assignment
- copy constructor
- copy elision
- default constructor
- `explicit`
- initialization
  - aggregate initialization
  - constant initialization
  - copy initialization
  - direct initialization
  - reference initialization
  - value initialization
  - zero initialization
- move assignment
- move constructor
- `new`

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/language/list_initialization&oldid=151772"