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
上面的大多数初始化都声明了一个int 或int 的数组,但是可以使用相同的语法来调用类类型的构造函数(例如构造Class 变量的两行)
除了在几乎任何可以初始化变量的上下文中都有效之外,列表初始化还可以与 C++11 的另一个新特性很好地交互:std::initializer_list 类模板。接受std::initializer_list 参数的构造函数可以传递任意长的值列表,构造函数可以通过std::initializer_list 的begin() 和end() 成员函数对其进行迭代。这个新特性的主要好处是它允许你用一组元素初始化一个容器,例如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 的赋值运算符将被调用,该临时为它的论点。