Initializes an object from a
brace-enclosed initializer 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) newT{arg1, arg2, ...}newT{.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 brace-enclosed initializer list
2) initialization of an unnamed temporary with a brace-enclosed initializer list
3) initialization of an object with dynamic storage duration with a
, where the initializer is a brace-enclosed initializer list
5) in a
of a constructor if a brace-enclosed initializer 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 brace-enclosed initializer list after an equals sign
7) in a function call expression, with a brace-enclosed initializer list used as an argument and list-initialization initializes the function parameter
8) in a return statement with a brace-enclosed initializer list used as the return expression and list-initialization initializes the returned object
9) in a
with a user-defined operator[], where list-initialization initializes the parameter of the overloaded operator
10) in an
, where list-initialization initializes the parameter of the overloaded operator
11)
or other constructor invocations, where a brace-enclosed initializer 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 is being list-initialized; U's constructor's parameter is)
Explanation
The effects of list-initialization of an object of type (possibly cv-qualified) T are:
If the brace-enclosed initializer list contains a
and T is not a reference type, T must be an aggregate class. The ordered identifiers in the designators of the designated initializer list must form a subsequence of the ordered identifiers in the direct non-static data members of T.
is performed.
(since C++20)If T is an aggregate class and the brace-enclosed initializer list, which does not contain a designated initializer list,(since C++20) has a single initializer clause of the same or derived type (possibly cv-qualified), the object is initialized from that initializer clause (by
for copy-list-initialization, or by
for direct-list-initialization).
Otherwise, if T is a character array and the brace-enclosed initializer list has a single initializer clause that is an appropriately-typed string literal, the array is
initialized from the string literal as usual
.
Otherwise, if T is an
,
is performed.
Otherwise, if the brace-enclosed initializer list is empty and T is a class type with a default constructor,
is performed.
Otherwise, if T is a specialization of
, the object is initialized as described
.
Otherwise, if T is a class type, the constructors of T are considered, in two phases:
All constructors that take
as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by
against a single argument of type
.
If the previous stage does not produce a match, all constructors of T participate in
against the set of arguments that consists of the initializer clauses of the brace-enclosed initializer 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
that with fixed underlying type U, the brace-enclosed initializer list has only one initializer v, and all following conditions are satisfied, then the enumeration is initialized with the result of converting v to U: The initialization is direct-list-initialization.
v is of
.
v is implicitly convertible to U.
The conversion from v to U is non-narrowing.
(since C++17)Otherwise (if T is not a class type), if the brace-enclosed initializer list has only one initializer clause 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 initializer clause, T is
(in direct-list-initialization) or
(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 initializer clause:
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 Ux[]H, where H is the initializer list(since C++20).
(since C++17)Otherwise, if the brace-enclosed initializer list has no initializer clause, T is
.
List-initializing
An object of type std::initializer_list<E> is constructed from an initializer list as if the compiler generated and
(since C++17) a
of type “array of NconstE”, where N is the number of initializer clauses in the initializer list; this is called the initializer list’s backing array.
Each element of the backing array is
with the corresponding initializer clause of the initializer list, and the std::initializer_list<E> object is constructed to refer to that array. A constructor or conversion function selected for the copy is required to be
in the context of the initializer list. If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.
The backing array has the same lifetime as any other
, except that initializing an
object from the backing array extends the lifetime of the array exactly like
binding a reference to a temporary
.
voidf(std::initializer_list<double>il);voidg(floatx){f({1,x,3});}voidh(){f({1,2,3});}structA{mutableinti;};voidq(std::initializer_list<A>);voidr(){q({A{1},A{2},A{3}});}// The initialization above will be implemented in a way roughly equivalent to below,// assuming that the compiler can construct an initializer_list object with a pair of// pointers, and with the understanding that `__b` does not outlive the call to `f`.voidg(floatx){constdouble__a[3]={double{1},double{x},double{3}};// backing arrayf(std::initializer_list<double>(__a,__a+3));}voidh(){staticconstexprdouble__b[3]={double{1},double{2},double{3}};// backing arrayf(std::initializer_list<double>(__b,__b+3));}voidr(){constA__c[3]={A{1},A{2},A{3}};// backing arrayq(std::initializer_list<A>(__c,__c+3));}Whether all backing arrays are distinct (that is, are stored in
) is unspecified:
boolfun(std::initializer_list<int>il1,std::initializer_list<int>il2){returnil2.begin()==il1.begin()+1;}booloverlapping=fun({1,2,3},{2,3,4});// the result is unspecified:// the back arrays can share// storage within {1, 2, 3, 4}Narrowing conversions
List-initialization limits the allowed
by prohibiting the following:
conversion from a floating-point type to an integer type
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 conversion result is a
and one of the following conditions is satisfied: The converted value is finite, and the conversion does not overflow.
The values before and after the conversion are not finite.
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
whose width w is less than that of its type (or, for an
, 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
any initializer clause that follows it in the brace-enclosed initializer list. This is in contrast with the arguments of a
, which are
(until C++17)
(since C++17).
A brace-enclosed initializer 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 brace-enclosed initializer list, so given the declaration template<classT>voidf(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 brace-enclosed initializer list as
in copy-list-initialization.
Also because a brace-enclosed initializer 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 brace-enclosed initializer list of a single initializer clause of the same type, but non-aggregates consider
constructors first:
structX{};// aggregatestructQ// non-aggregate{Q()=default;Q(Qconst&)=default;Q(std::initializer_list<Q>){}};intmain(){Xx;Xx2=X{x};// copy-constructor (not aggregate initialization)Qq;Qq2=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 macroValueStdFeature
(C++11)List-initialization and
Example
Run this code
#include<iostream>#include<map>#include<string>#include<vector>structFoo{std::vector<int>mem={1,2,3};// list-initialization of a non-static memberstd::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}intmain(){intn0{};// value-initialization (to zero)intn1{1};// direct-list-initializationstd::strings1{'a','b','c','d'};// initializer-list constructor callstd::strings2{s1,2,2};// regular constructor callstd::strings3{0x61,'a'};// initializer-list ctor is preferred to (int, char)intn2={1};// copy-list-initializationdoubled=double{1.2};// list-initialization of a prvalue, then copy-initautos4=std::string{"HelloWorld"};// same as above, no temporary// created since C++17std::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';constint(&ar)[2]={1,2};// binds an lvalue reference to a temporary arrayint&&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 conversionunsignedcharuc1{10};// okay// unsigned char uc2{-1}; // error: narrowing conversionFoof;std::cout<<n0<<' '<<n1<<' '<<n2<<'\n'<<s1<<' '<<s2<<' '<<s3<<'\n';for(autop:m)std::cout<<p.first<<' '<<p.second<<'\n';for(auton:f.mem)std::cout<<n<<' ';for(auton:f.mem2)std::cout<<n<<' ';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
C++11 list-initializing a reference with a brace-enclosed initializer list of a
single initializer clause always bound the reference to a temporary bind to that initializer
clause if valid
C++11 the lifetime of the backing array was not correctly specified specified same as other
temporary objects
C++11 initialization considered first for initialization from {}aggregate initialization
considered first
C++11 the type of the backing array lacked constconst added
C++11 same-type initialization of aggregates and character
arrays was prohibited; initializer-list constructors had
priority over copy constructors for single-clause lists same-type initialization
allowed; single-clause
lists initialize directly
C++11 when list-initializing a reference with an initializer clause 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
C++11 initializer-list constructors lost to copy
constructors when list-initializing X from {X}non-aggregates consider
initializer-lists first
C++17 enumerations could be list-initialized from non-scalar values prohibited
C++11 the resolution of
made clear
that temporaries could be direct-list-initialized they are copy-list-initialized
when list-initializing references
C++17 direct-list-initialization of an enum allowed too many source types restricted
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
C++20 references to aggregate classes could not
be initialized by designated initializer lists allowed
C++11 list-initialization did not ignore the top-level cv-qualification ignores
C++11 floating-point conversions that overflow were not narrowing they are narrowing
C++11 conversion from a pointer/pointer-to-member
to bool was not narrowing considered narrowing
C++11 backing arrays with overlapping lifetime could not overlap they may overlap See also