c++ - 我们可以在哪里使用列表初始化?

标签 c++ c++11 initialization aggregate

This question已经涵盖了 POD 和聚合是什么,并提供了一些聚合初始化的示例。

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

还有你可以在哪里使用(没有更好的术语)列表分配?

答案应该同时涉及 C++03 和 C++11,突出它们之间的差异。

最佳答案

C++03

列表初始化

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

int i = { 0 };
POD pod = { 0, 1, 2 };

列表赋值

您不能在 C++03 的任何地方使用“列表赋值”。 [expr.ass]/1 中显示的语法不允许在赋值右侧使用花括号。

C++11

列表初始化

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

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

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

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

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

唯一一次列表初始化没有做正确的事情是,如果类有另一个构造函数采用 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 };

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

列表赋值

在 C++11 中,您可以使用“列表赋值”

  • 分配给标量类型时,如果 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 };
    }
    

    main 的最后一行braced-init-list 将被隐式转换为临时 A然后是 B 的赋值运算符将使用该临时参数作为参数调用。

关于c++ - 我们可以在哪里使用列表初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13267277/

相关文章:

c++ - reinterpret_cast 与严格别名

c++ - 为什么 Visual C++ 不在特定函数中命中断点或单步执行?

c++ - 模拟 C++ 标准库

c++11 - C11 和 C++11 中转换 UTF-8 的标准方法?

c++ - 静态注册会导致惨败吗

c# - InitializeComponent 在两个构造函数中,还是在一个具有构造函数继承的构造函数中?

c++ - 等待 20 秒后才更新数据库记录,以便可以接收到最大记录

c++ - g++ std::is_function 实现:_ArgTypes 后跟 6 个句点是什么意思?

c++ - 如何为 c++11 更正以下生产者消费者代码

c++ - 在类的构造函数中初始化一个二维 vector