list initialization



Initializes an object from braced-init-list

Contents

 [hide

[edit] Syntax

[edit] direct-list-initialization
 
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) 
 
[edit] copy-list-initialization
 
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:

  • 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 brace-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 (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

[edit] Explanation

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

  • If T is an aggregate type and the initializer 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 initializer list has a single element that is an appropriately-typed string literal, the array is initialized from the string literal as usual
(since C++14)
  • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
(until C++14)
  • Otherwise, If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
(since C++14)
  • 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 time initialized from (until C++17) the braced-init-list.
  • Otherwise, the constructors of T are considered, in two phases:
  • 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 a enumeration type that is either scoped or unscoped with fixed underlying type, and if the braced-init-list has only one initializer, and if the conversion from the initializer to the underlying type is non-narrowing, and if the initialization is direct-list-initialization, then the enumeration is initialized with the result of converting the initializer to its underlying type.
(since C++17)
  • Otherwise (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type that is compatible with 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 isn't compatible with the type of the element, a temporary of the referenced type is list-initialized, and the reference is bound to that temporary (until C++17)the reference is direct-initialized from a prvalue expression of the referenced type that list-initializes its result object (since C++17). (this fails if the reference is a non-const lvalue reference)

[edit] 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
  • 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 source is a constant expression whose value can be stored exactly in the target type

[edit] Notes

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. A special exception is made for type deduction using the keyword auto , which deduces any braced-init-list as std::initializer_list

Also because 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-lists of the same type, but non-aggregates consider initializer_list constructors first:

struct X {
    X() = default;
    X(const X&) = default;
};
 
struct Q {
    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)
}
(since C++14)

[edit] Example


#include <iostream>
#include <vector>
#include <map>
#include <string>
 
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 temporary, then copy-init
 
    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 a lvalue reference to a temporary array
    int&& r1 = {1}; // binds a 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 << ' ';
}

Compiler messages:

main.cpp: In function 'int main()':
main.cpp:26:12: warning: unused variable 'd' [-Wunused-variable]
     double d = double{1.2}; // list-initialization of a temporary, then copy-init
            ^
main.cpp:37:17: warning: unused variable 'ar' [-Wunused-variable]
     const int (&ar)[2] = {1,2}; // binds a lvalue reference to a temporary array
                 ^~
main.cpp:38:11: warning: unused variable 'r1' [-Wunused-variable]
     int&& r1 = {1}; // binds a rvalue reference to a temporary int
           ^~
main.cpp:42:19: warning: unused variable 'uc1' [-Wunused-variable]
     unsigned char uc1{10}; // okay
                   ^~~

Output:

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

[edit] Defect reports

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

DRApplied toBehavior as publishedCorrect behavior
CWG 1467C++14same-type initialization of aggregates and char arrays was prohibitedsame-type initialization allowed
CWG 1467C++14std::initializer_list constructors had priority over copy constructors for single-element listssingle-element lists initialize directly

[edit] See also



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值