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
上面的大多数初始化都声明了 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 }
而不是构造容器然后插入值。
列表初始化也可以用于括号初始化列表中的元素,允许嵌套列表初始化,例如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/