[dcl.init.list]

# 9 Declarations [[dcl]](./#dcl)

## 9.5 Initializers [[dcl.init]](dcl.init#list)

### 9.5.5 List-initialization [dcl.init.list]

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6366)

[*List-initialization*](#def:list-initialization "9.5.5 List-initialization [dcl.init.list]") is initialization of an object or reference from a[*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")[.](#1.sentence-1)

Such an initializer is called an [*initializer list*](#def:initializer_list), and
the comma-separated[*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")*s* of the [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") or[*designated-initializer-clause*](dcl.init.general#nt:designated-initializer-clause "9.5.1 General [dcl.init.general]")*s* of the [*designated-initializer-list*](dcl.init.general#nt:designated-initializer-list "9.5.1 General [dcl.init.general]") are called the [*elements*](#def:elements) of the initializer list[.](#1.sentence-2)

An initializer list may be empty[.](#1.sentence-3)

List-initialization can occur in direct-initialization or copy-initialization contexts;
list-initialization in a direct-initialization context is called[*direct-list-initialization*](#def:direct-list-initialization "9.5.5 List-initialization [dcl.init.list]") and list-initialization in a
copy-initialization context is called [*copy-list-initialization*](#def:copy-list-initialization "9.5.5 List-initialization [dcl.init.list]")[.](#1.sentence-4)

Direct-initialization that is not list-initialization is called[*direct-non-list-initialization*](#def:direct-non-list-initialization "9.5.5 List-initialization [dcl.init.list]")[.](#1.sentence-5)

[*Note [1](#note-1)*:

List-initialization can be used

- [(1.1)](#1.1)

as the initializer in a variable definition ([[dcl.init]](dcl.init "9.5 Initializers")),

- [(1.2)](#1.2)

as the initializer in a [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New")),

- [(1.3)](#1.3)

in a return statement ([[stmt.return]](stmt.return "8.8.4 The return statement")),

- [(1.4)](#1.4)

as a [*for-range-initializer*](stmt.pre#nt:for-range-initializer "8.1 Preamble [stmt.pre]") ([[stmt.iter]](stmt.iter "8.6 Iteration statements")),

- [(1.5)](#1.5)

as a function argument ([[expr.call]](expr.call "7.6.1.3 Function call")),

- [(1.6)](#1.6)

as a template argument ([[temp.arg.nontype]](temp.arg.nontype "13.4.3 Constant template arguments")),

- [(1.7)](#1.7)

as a subscript ([[expr.sub]](expr.sub "7.6.1.2 Subscripting")),

- [(1.8)](#1.8)

as an argument to a constructor invocation ([[dcl.init]](dcl.init "9.5 Initializers"), [[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)")),

- [(1.9)](#1.9)

as an initializer for a non-static data member ([[class.mem]](class.mem "11.4 Class members")),

- [(1.10)](#1.10)

in a [*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members")), or

- [(1.11)](#1.11)

on the right-hand side of an assignment ([[expr.assign]](expr.assign "7.6.19 Assignment and compound assignment operators"))[.](#1.sentence-6)

[*Example [1](#example-1)*: int a = {1};
std::complex<double> z{1,2};new std::vector<std::string>{"once", "upon", "a", "time"}; // 4 string elements f( {"Nicholas","Annemarie"} ); // pass list of two elementsreturn { "Norah" }; // return list of one elementint* e {}; // initialization to zero / null pointer x = double{1}; // explicitly construct a double std::map<std::string,int> anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} }; â *end example*]

â *end note*]

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6413)

A constructor is an [*initializer-list constructor*](#def:initializer-list_constructor "9.5.5 List-initialization [dcl.init.list]") if its first parameter is
of type std​::​initializer_list<E> or reference tocv std​::​initializer_list<E> for some type E, and either there are no other
parameters or else all other parameters have default arguments ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#2.sentence-1)

[*Note [2](#note-2)*:

Initializer-list constructors are favored over other constructors in
list-initialization ([[over.match.list]](over.match.list "12.2.2.8 Initialization by list-initialization"))[.](#2.sentence-2)

Passing an initializer list as the argument
to the constructor template template<class T> C(T) of a class C does not
create an initializer-list constructor, because an initializer list argument causes the
corresponding parameter to be a non-deduced context ([[temp.deduct.call]](temp.deduct.call "13.10.3.2 Deducing template arguments from a function call"))[.](#2.sentence-3)

â *end note*]

The templatestd​::​initializer_list is not predefined;
if a standard library declaration ([[initializer.list.syn]](initializer.list.syn "17.11.2 Header <initializer_­list> synopsis"), [[std.modules]](std.modules "16.4.2.4 Modules"))
of std​::​initializer_list is not reachable from ([[module.reach]](module.reach "10.7 Reachability"))
a use of std​::​initializer_list â
even an implicit use in which the type is not named ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")) â
the program is ill-formed[.](#2.sentence-4)

[3](#3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6433)

List-initialization of an object or reference of type *cv* T is defined as follows:

- [(3.1)](#3.1)

  If the [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") contains a [*designated-initializer-list*](dcl.init.general#nt:designated-initializer-list "9.5.1 General [dcl.init.general]") andT is not a reference type,T shall be an aggregate class[.](#3.1.sentence-1)
  The ordered [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")*s* in the [*designator*](dcl.init.general#nt:designator "9.5.1 General [dcl.init.general]")*s* of the [*designated-initializer-list*](dcl.init.general#nt:designated-initializer-list "9.5.1 General [dcl.init.general]") shall form a subsequence
of the ordered [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")*s* in the direct non-static data members of T[.](#3.1.sentence-2)
  Aggregate initialization is performed ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"))[.](#3.1.sentence-3)
  [*Example [2](#example-2)*: struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error: designator order does not match declaration order A b{.x = 1, .z = 2}; // OK, b.y initialized to 0 â *end example*]

- [(3.2)](#3.2)

  If T is an aggregate class and the initializer list has a single element
of type *cv1* U,
where U is T or a class derived from T,
the object is initialized from that element (by copy-initialization for
copy-list-initialization, or by direct-initialization for
direct-list-initialization)[.](#3.2.sentence-1)

- [(3.3)](#3.3)

  Otherwise, if T is a character array and the initializer list has a
single element that is an appropriately-typed [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]") ([[dcl.init.string]](dcl.init.string "9.5.3 Character arrays")),
initialization is performed as described in that subclause[.](#3.3.sentence-1)

- [(3.4)](#3.4)

  Otherwise, if T is an aggregate, aggregate initialization is
performed ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"))[.](#3.4.sentence-1)
  [*Example [3](#example-3)*: double ad[] = { 1, 2.0 }; // OKint ai[] = { 1, 2.0 }; // error: narrowingstruct S2 {int m1; double m2, m3;};
S2 s21 = { 1, 2, 3.0 }; // OK S2 s22 { 1.0, 2, 3 }; // error: narrowing S2 s23 { }; // OK, default to 0,0,0 â *end example*]

- [(3.5)](#3.5)

  Otherwise, if the initializer list has no elements and T is a class type with a
default constructor, the object is value-initialized[.](#3.5.sentence-1)

- [(3.6)](#3.6)

  Otherwise, if T is a specialization of std​::​initializer_list,
the object is constructed as described below[.](#3.6.sentence-1)

- [(3.7)](#3.7)

  Otherwise, if T is a class type, constructors are considered[.](#3.7.sentence-1)
  The applicable constructors are enumerated and
the best one is chosen through overload resolution ([[over.match]](over.match "12.2 Overload resolution"), [[over.match.list]](over.match.list "12.2.2.8 Initialization by list-initialization"))[.](#3.7.sentence-2)
  If a narrowing
conversion (see below) is required to convert any of the arguments, the program is
ill-formed[.](#3.7.sentence-3)
  [*Example [4](#example-4)*: struct S { S(std::initializer_list<double>); // #1 S(std::initializer_list<int>); // #2 S(std::initializer_list<S>); // #3 S(); // #4// ...};
S s1 = { 1.0, 2.0, 3.0 }; // invoke #1 S s2 = { 1, 2, 3 }; // invoke #2 S s3{s2}; // invoke #3 (not the copy constructor) S s4 = { }; // invoke #4 â *end example*]
  [*Example [5](#example-5)*: struct Map { Map(std::initializer_list<std::pair<std::string,int>>);};
Map ship = {{"Sophie",14}, {"Surprise",28}}; â *end example*]
  [*Example [6](#example-6)*: struct S {// no initializer-list constructors S(int, double, double); // #1 S(); // #2// ...};
S s1 = { 1, 2, 3.0 }; // OK, invoke #1 S s2 { 1.0, 2, 3 }; // error: narrowing S s3 { }; // OK, invoke #2 â *end example*]

- [(3.8)](#3.8)

  Otherwise, if T is an enumeration
with a fixed underlying type ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations")) U,
the [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") has a single element v of scalar type,v can be implicitly converted to U, and
the initialization is direct-list-initialization,
the object is initialized with the value T(v) ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"));
if a narrowing conversion is required to convert v to U, the program is ill-formed[.](#3.8.sentence-1)
  [*Example [7](#example-7)*: enum byte : unsigned char { };
byte b { 42 }; // OK byte c = { 42 }; // error byte d = byte{ 42 }; // OK; same value as b byte e { -1 }; // errorstruct A { byte b; };
A a1 = { { 42 } }; // error A a2 = { byte{ 42 } }; // OKvoid f(byte);
f({ 42 }); // errorenum class Handle : uint32_t { Invalid = 0 };
Handle h { 42 }; // OK â *end example*]

- [(3.9)](#3.9)

  Otherwise, if
the initializer list
is not a [*designated-initializer-list*](dcl.init.general#nt:designated-initializer-list "9.5.1 General [dcl.init.general]") and
has a single element of type E and eitherT is not a reference type or its referenced type is
reference-related to E, the object or reference is initialized
from that element (by copy-initialization for copy-list-initialization,
or by direct-initialization for direct-list-initialization);
if a narrowing conversion (see below) is required
to convert the element to T, the program is ill-formed[.](#3.9.sentence-1)
  [*Example [8](#example-8)*: int x1 {2}; // OKint x2 {2.0}; // error: narrowing â *end example*]

- [(3.10)](#3.10)

  Otherwise, if T is a reference type, a prvalue is generated[.](#3.10.sentence-1)
  The prvalue initializes its result object by copy-list-initialization from the initializer list[.](#3.10.sentence-2)
  The prvalue is then used to direct-initialize the reference[.](#3.10.sentence-3)
  The type of the prvalue is the type referenced by T,
unless T is âreference to array of unknown bound of Uâ,
in which case the type of the prvalue is
the type of x in the declaration U x[] H,
where H is the initializer list[.](#3.10.sentence-4)
  [*Note [3](#note-3)*:
  As usual, the binding will fail and the program is ill-formed if
the reference type is an lvalue reference to a non-const type[.](#3.10.sentence-5)
 â *end note*]
  [*Example [9](#example-9)*: struct S { S(std::initializer_list<double>); // #1 S(const std::string&); // #2// ...};const S& r1 = { 1, 2, 3.0 }; // OK, invoke #1const S& r2 { "Spinach" }; // OK, invoke #2 S& r3 = { 1, 2, 3 }; // error: initializer is not an lvalueconst int& i1 = { 1 }; // OKconst int& i2 = { 1.1 }; // error: narrowingconst int (&iar)[2] = { 1, 2 }; // OK, iar is bound to temporary arraystruct A { } a;struct B { explicit B(const A&); };const B& b2{a}; // error: cannot copy-list-initialize B temporary from Astruct C { int x; };
C&& c = { .x = 1 }; // OK â *end example*]

- [(3.11)](#3.11)

  Otherwise, if the initializer list has no elements, the object is
value-initialized[.](#3.11.sentence-1)
  [*Example [10](#example-10)*: int** pp {}; // initialized to null pointer â *end example*]

- [(3.12)](#3.12)

  Otherwise, the program is ill-formed[.](#3.12.sentence-1)
  [*Example [11](#example-11)*: struct A { int i; int j; };
A a1 { 1, 2 }; // aggregate initialization A a2 { 1.2 }; // error: narrowingstruct B { B(std::initializer_list<int>);};
B b1 { 1, 2 }; // creates initializer_list<int> and calls constructor B b2 { 1, 2.0 }; // error: narrowingstruct C { C(int i, double j);};
C c1 = { 1, 2.2 }; // calls constructor with arguments (1, 2.2) C c2 = { 1.1, 2 }; // error: narrowingint j { 1 }; // initialize to 1int k { }; // initialize to 0 â *end example*]

[4](#4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6651)

Within the [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") of a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]"),
the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")*s*, including any that result from pack
expansions ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates")), are evaluated in the order in which they
appear[.](#4.sentence-1)

That is, every value computation and side effect associated with a
given [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]") is sequenced before every value
computation and side effect associated with any [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]") that follows it in the comma-separated list of the [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]")[.](#4.sentence-2)

[*Note [4](#note-4)*:

This evaluation ordering holds regardless of the semantics of the
initialization; for example, it applies when the elements of the[*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") are interpreted as arguments of a constructor
call, even though ordinarily there are no sequencing constraints on the
arguments of a call[.](#4.sentence-3)

â *end note*]

[5](#5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6667)

An object of type std​::​initializer_list<E> is constructed from
an initializer list as if
the implementation generated and materialized ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion"))
a prvalue of type âarray of N const Eâ,
where N is the number of elements in the initializer list;
this is called the initializer list's [*backing array*](#def:array,backing "9.5.5 List-initialization [dcl.init.list]")[.](#5.sentence-1)

Each element of the backing array is copy-initialized with the
corresponding element of the initializer list, and thestd​::​initializer_list<E> object is constructed to refer to that array[.](#5.sentence-2)

[*Note [5](#note-5)*:

A constructor or conversion function selected for the copy needs to be
accessible ([[class.access]](class.access "11.8 Member access control")) in the context of the initializer list[.](#5.sentence-3)

â *end note*]

If a narrowing conversion is required to initialize any of the elements,
the program is ill-formed[.](#5.sentence-4)

[*Note [6](#note-6)*:

Backing arrays are potentially non-unique objects ([[intro.object]](intro.object "6.8.2 Object model"))[.](#5.sentence-5)

â *end note*]

[6](#6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6687)

The backing array has the same lifetime as any other temporary
object ([[class.temporary]](class.temporary "6.8.7 Temporary objects")), except that initializing aninitializer_list object from the array extends the lifetime of
the array exactly like binding a reference to a temporary[.](#6.sentence-1)

[*Example [12](#example-12)*: void f(std::initializer_list<double> il);void g(float x) { f({1, x, 3});}void h() { f({1, 2, 3});}struct A {mutable int i;};void q(std::initializer_list<A>);void r() { q({A{1}, A{2}, A{3}});}

The initialization will be implemented in a way roughly equivalent to this:void g(float x) {const double __a[3] = {double{1}, double{x}, double{3}}; // backing array f(std::initializer_list<double>(__a, __a+3));}void h() {static constexpr double __b[3] = {double{1}, double{2}, double{3}}; // backing array f(std::initializer_list<double>(__b, __b+3));}void r() {const A __c[3] = {A{1}, A{2}, A{3}}; // backing array q(std::initializer_list<A>(__c, __c+3));} assuming that the implementation
can construct an initializer_list object with a pair of pointers, and
with the understanding that __b does not outlive the call to f[.](#6.sentence-2)

â *end example*]

[*Example [13](#example-13)*: typedef std::complex<double> cmplx;
std::vector<cmplx> v1 = { 1, 2, 3 };

void f() { std::vector<cmplx> v2{ 1, 2, 3 };
 std::initializer_list<int> i3 = { 1, 2, 3 };}struct A { std::initializer_list<int> i4;
 A() : i4{ 1, 2, 3 } {} // ill-formed, would create a dangling reference};

For v1 and v2, the initializer_list object
is a parameter in a function call, so the array created for{ 1, 2, 3 } has full-expression lifetime[.](#6.sentence-3)

For i3, the initializer_list object is a variable,
so the array persists for the lifetime of the variable[.](#6.sentence-4)

For i4, the initializer_list object is initialized in
the constructor's [*ctor-initializer*](class.base.init#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") as if by binding
a temporary array to a reference member, so the program is
ill-formed ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members"))[.](#6.sentence-5)

â *end example*]

[7](#7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L6758)

A [*narrowing conversion*](#def:conversion,narrowing "9.5.5 List-initialization [dcl.init.list]") is an implicit conversion

- [(7.1)](#7.1)

from a floating-point type to an integer type, or

- [(7.2)](#7.2)

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 result of the conversion is a constant expression and
either its value is finite and the conversion did not overflow, or
the values before and after the conversion are not finite, or

- [(7.3)](#7.3)

from an integer type or unscoped enumeration type to a floating-point type, except
where the source is a constant expression and the actual value after conversion will fit
into the target type and will produce the original value when converted back to the
original type, or

- [(7.4)](#7.4)

from an integer type or unscoped enumeration type to an integer type that cannot
represent all the values of the original type, except where
  * [(7.4.1)](#7.4.1)

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

  * [(7.4.2)](#7.4.2)

the source is a constant
expression whose value after integral promotions will fit into the target type, or

- [(7.5)](#7.5)

from a pointer type or a pointer-to-member type to bool[.](#7.sentence-1)

[*Note [7](#note-7)*:

As indicated above, such conversions are not allowed at the top level in
list-initializations[.](#7.sentence-2)

â *end note*]

[*Example [14](#example-14)*: int x = 999; // x is not a constant expressionconst int y = 999;const int z = 99;char c1 = x; // OK, though it potentially narrows (in this case, it does narrow)char c2{x}; // error: potentially narrowschar c3{y}; // error: narrows (assuming char is 8 bits)char c4{z}; // OK, no narrowing neededunsigned char uc1 = {5}; // OK, no narrowing neededunsigned char uc2 = {-1}; // error: narrowsunsigned int ui1 = {-1}; // error: narrowssigned int si1 ={ (unsigned int)-1 }; // error: narrowsint ii = {2.0}; // error: narrowsfloat f1 { x }; // error: potentially narrowsfloat f2 { 7 }; // OK, 7 can be exactly represented as a floatbool b = {"meow"}; // error: narrowsint f(int);int a[] = { 2, f(2), f(2.0) }; // OK, the double-to-int conversion is not at the top level â *end example*]
