我们在哪里可以使用列表初始化

Luc*_*ore 13 c++ aggregate initialization c++11

这个问题已经涵盖了POD和聚合的内容,并提供了有关聚合初始化的一些示例.

这里的问题是哪里可以使用列表初始化?

您还可以哪里使用(缺少更好的术语)列表分配?

答案应该同时处理C++ 03和C++ 11,突出它们之间的差异.

Jon*_*ely 20

C++ 03

列表初始化

在C++ 03中,您只能对聚合(C++ 03 [dcl.init.aggr])和标量(C++ 03 [dcl.init]/13)类型使用列表初始化:

int i = { 0 };
POD pod = { 0, 1, 2 };
Run Code Online (Sandbox Code Playgroud)

列表分配

您无法在C++ 03中的任何位置使用"list-assignment".[expr.ass]/1中显示的语法不允许赋值右侧的支撑列表.

C++ 11

列表初始化

在C++ 11中,您可以在任何可以创建变量的地方使用列表初始化(参见C++ 11中的[dcl.init]和[dcl.init.list]/1,其中列出了允许列表初始化的上下文) )例如

struct Base { };

struct Class : Base
{
    int mem{ 0 };  // init non-static data member

    Class(int i)
    : Base{}   // init base class
    , mem{i}   // init member
    {
      int j{i};   // init local var

      int k = int{0};  // init temporary

      f( { 1 } );  // init function arg

      int* p = new int{1};  // new init

      // int k(int());  // most vexing parse, declares function
      int k{ int{} };   // ok, declares variable

      int i[4]{ 1,2,3,4 };   // init array
    }

    Class f(int i)
    {
      return { i };   // init return value
    }
};

Class c{1};   // init global var
Run Code Online (Sandbox Code Playgroud)

上面的大多数初始化都声明了一个int或者数组,int但是可以使用相同的语法来调用类类型的构造函数(比如构造Class变量的两行)

除了在几乎任何可以初始化变量的上下文中都有效之外,列表初始化还可以与C++ 11的另一个新功能(std::initializer_list类模板)很好地交互.接受一个std::initializer_list参数的构造函数可以传递一个任意长的值列表,构造函数可以通过这些值遍历begin()end()成员函数std::initializer_list.这个新功能的主要好处是它允许您使用一组元素初始化容器,例如,vector<int> v{ 0, 1, 2, 3, 4, 5 }而不是构造容器,然后插入值.

列表初始化也可以用于braced-init-list中的元素,允许嵌套列表初始化,Map m{ {a, b}, {c, d} }而不是Map m{ Map::value_type(a, b), Map::value_type(c, d) }

唯一的时间列表初始化没有做正确的事情是当尝试通过调用构造函数来构造类类型时,如果类有另一个构造函数采用a std::initializer_list,因为列表初始化总是更喜欢构造函数采用std::initializer_list例如

// attempts to create vector of 5 elements, [1,1,1,1,1]
// but actually creates a vector with two elements, [5,1] 
std::vector<int> v{ 5, 1 };
Run Code Online (Sandbox Code Playgroud)

这不会调用vector(size_type, const int&)构造函数,而是调用vector(initializer_list<int>)构造函数.

列表分配

在C++ 11中,您可以使用"list-assignment"

  • 当分配给标量类型时,如果braced-init-list有一个可转换(不缩小)到变量类型的元素(参见[expr.ass]/9)
  • 当赋值的左操作数是具有用户定义的赋值运算符的类类型时,在这种情况下,braced-init-list用于初始化运算符的参数(参见[expr.ass]/9).这包括两种情况,例如右操作数中operator=(std::initializer_list<T>)braced-init-list的元素可以转换为T,例如对于std::vector<int> v上面的情况,v = { 1, 2, 3 }将用[1,2,3]替换容器的内容,并且当braced-init-list可以通过合适的构造函数,例如,隐式转换为运算符的参数类型

    struct A {
      int i;
      int j;
    };
    
    struct B {
      B& operator=(const A&);
    };
    
    int main() {
      B b;
      b = { 0, 1 };
    }
    
    Run Code Online (Sandbox Code Playgroud)

    2005年的最后一行main支撑,初始化列表将被隐式转换到一个临时A随后的赋值运算符B将与暂时性的,因为它的参数来调用.