Initializes an object from braced-init-list.
T object { arg1, arg2, ... };
| (1) | |||
T { arg1, arg2, ... }
| (2) | |||
new T { arg1, arg2, ... }
| (3) | |||
Class { T member { arg1, arg2, ... }; };
| (4) | |||
Class:: Class() : member { arg1, arg2, ... } {...
| (5) |
T object = { arg1, arg2, ... };
| (6) | |||
function ({ arg1, arg2, ... })
| (7) | |||
return { arg1, arg2, ... };
| (8) | |||
object [{ arg1, arg2, ... }]
| (9) | |||
object = { arg1, arg2, ... }
| (10) | |||
U ({ arg1, arg2, ... })
| (11) | |||
Class { T member = { arg1, arg2, ... }; };
| (12) |
List initialization is performed in the following situations:
return
operator[]
, where list-initialization initializes the parameter of the overloaded operatorThe effects of list-initialization of an object of type T
are:
| (since C++20) |
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). 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. T
is an aggregate type, aggregate initialization is performed. T
is a class type with a default constructor, value-initialization is performed. 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. T
are considered, in two phases: 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
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).
v to U . | (since C++17) |
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. T
is a reference type that is not compatible with the type of the element:
| (until C++17) |
| (since C++17) |
T
is value-initialized. List-initialization limits the allowed implicit conversions by prohibiting the following:
| (until C++23) |
| (since C++23) |
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 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 |
#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
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 |
explicit
new
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/list_initialization