6.20. 列表初始化

Tip

你可以用列表初始化。

早在 C++03 里,聚合类型(aggregate types)就已经可以被列表初始化了,比如数组和不自带构造函数的结构体:

  1. struct Point { int x; int y; };
  2. Point p = {1, 2};

C++11 中,该特性得到进一步的推广,任何对象类型都可以被列表初始化。示范如下:

  1. // Vector 接收了一个初始化列表。
  2. vector<string> v{"foo", "bar"};
  3.  
  4. // 不考虑细节上的微妙差别,大致上相同。
  5. // 您可以任选其一。
  6. vector<string> v = {"foo", "bar"};
  7.  
  8. // 可以配合 new 一起用。
  9. auto p = new vector<string>{"foo", "bar"};
  10.  
  11. // map 接收了一些 pair, 列表初始化大显神威。
  12. map<int, string> m = {{1, "one"}, {2, "2"}};
  13.  
  14. // 初始化列表也可以用在返回类型上的隐式转换。
  15. vector<int> test_function() { return {1, 2, 3}; }
  16.  
  17. // 初始化列表可迭代。
  18. for (int i : {-1, -2, -3}) {}
  19.  
  20. // 在函数调用里用列表初始化。
  21. void TestFunction2(vector<int> v) {}
  22. TestFunction2({1, 2, 3});

用户自定义类型也可以定义接收 std::initializer_list<T> 的构造函数和赋值运算符,以自动列表初始化:

  1. class MyType {
  2. public:
  3. // std::initializer_list 专门接收 init 列表。
  4. // 得以值传递。
  5. MyType(std::initializer_list<int> init_list) {
  6. for (int i : init_list) append(i);
  7. }
  8. MyType& operator=(std::initializer_list<int> init_list) {
  9. clear();
  10. for (int i : init_list) append(i);
  11. }
  12. };
  13. MyType m{2, 3, 5, 7};

最后,列表初始化也适用于常规数据类型的构造,哪怕没有接收 std::initializer_list<T> 的构造函数。

  1. double d{1.23};
  2. // MyOtherType 没有 std::initializer_list 构造函数,
  3. // 直接上接收常规类型的构造函数。
  4. class MyOtherType {
  5. public:
  6. explicit MyOtherType(string);
  7. MyOtherType(int, string);
  8. };
  9. MyOtherType m = {1, "b"};
  10. // 不过如果构造函数是显式的(explict),您就不能用 `= {}` 了。
  11. MyOtherType m{"b"};

千万别直接列表初始化 auto 变量,看下一句,估计没人看得懂:

Warning

  1. auto d = {1.23}; // d 即是 std::initializer_list<double>
  1. auto d = double{1.23}; // 善哉 -- d 即为 double, 并非 std::initializer_list.

至于格式化,参见 9.7. 列表初始化格式.