Where can we use list initialization?(我们可以在哪里使用列表初始化?)
问题描述
这个问题已经涵盖了 POD 和聚合是什么,并提供了一些聚合初始化的示例.
This question already covers what PODs and aggregates are, and provides some examples on aggregate initialization.
这里的问题是在哪里可以使用列表初始化?
还有你可以在哪里使用(没有更好的术语)列表分配?
Also where can you use (in lack of a better term) list assignment?
答案应该同时涉及 C++03 和 C++11,突出它们之间的差异.
An answer should deal with both C++03 and C++11, highlighting the differences between them.
推荐答案
C++03
列表初始化
在 C++03 中,您只能对聚合 (C++03 [dcl.init.aggr]) 和标量 (C++03 [dcl.init]/13) 类型使用列表初始化:
C++03
List initialization
In C++03 you can only use list-initialization for aggregates (C++03 [dcl.init.aggr]) and scalar (C++03 [dcl.init]/13) types:
int i = { 0 };
POD pod = { 0, 1, 2 };
列表赋值
您不能在 C++03 的任何地方使用列表赋值".[expr.ass]/1 中显示的语法不允许在赋值右侧使用花括号.
List assignment
You could not use "list-assignment" anywhere in C++03. The grammar shown in [expr.ass]/1 does not allow a braced list on the right of an assignment.
在 C++11 中,您几乎可以在任何可以创建变量的地方使用列表初始化(参见 C++11 中的 [dcl.init] 和 [dcl.init.list]/1,其中列出了 list-允许初始化)例如
In C++11 you can use list-initialization pretty much anywhere you can create a variable (see [dcl.init] in C++11 and [dcl.init.list]/1 which lists contexts where list-initialization is allowed) e.g.
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
变量)
Most of the initializations above declare an int
or array of int
but the same syntax can be used to call a constructor for a class type (like the two lines that construct a Class
variable)
除了在几乎任何可以初始化变量的上下文中都有效之外,列表初始化还可以与 C++11 的另一个新特性很好地交互:std::initializer_list
类模板.接受 std::initializer_list
参数的构造函数可以传递任意长的值列表,构造函数可以通过 begin()
和 end 对其进行迭代()
std::initializer_list
的成员函数.这个新特性的主要好处是它允许你用一组元素初始化一个容器,例如向量
而不是构造容器然后插入值.
As well as being valid in almost any context where you can initialize a variable, list-initialization also interacts well with another new feature of C++11: the std::initializer_list
class template. A constructor that takes a std::initializer_list
argument can be passed an arbitrarily-long list of values, which the constructor can iterate over via begin()
and end()
member functions of the std::initializer_list
. The main benefit of this new feature is that it allows you to initialize a container with a set of elements, e.g. vector<int> v{ 0, 1, 2, 3, 4, 5 }
rather than constructing the container and then inserting values.
列表初始化也可以用于括号初始化列表中的元素,允许嵌套列表初始化,例如Map m{ {a, b}, {c, d} }
而不是 Map m{ Map::value_type(a, b), Map::value_type(c, d) }
List-initialization can also be used for elements within a braced-init-list, allowing nested list-initialization e.g. Map m{ {a, b}, {c, d} }
rather than Map m{ Map::value_type(a, b), Map::value_type(c, d) }
唯一一次列表初始化没有做正确的事情是,当类有另一个构造函数以 std::initializer_list
作为列表时,尝试通过调用构造函数来构造类类型-initialization 总是喜欢构造函数采用 std::initializer_list
例如
The only time list-initialization doesn't do the right thing is when trying to construct a class type by calling a constructor if the class has another constructor taking a std::initializer_list
, as list-initialization will always prefer the constructor taking a std::initializer_list
e.g.
// 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>)
构造函数.
This doesn't call the vector(size_type, const int&)
constructor, instead of calls the vector(initializer_list<int>)
constructor.
在 C++11 中,您可以使用列表赋值"
In C++11 you can use "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 可以通过合适的构造函数隐式转换为运算符的参数类型,例如
- when assigning to a scalar type, if the braced-init-list has a single element that is convertible (without narrowing) to the variable's type (see [expr.ass]/9)
when the left operand of the assignment is a class type with a user-defined assignment operator, in which case the braced-init-list is used to initialize the argument of the operator (see [expr.ass]/9). This includes both cases like
operator=(std::initializer_list<T>)
where the elements of the braced-init-list in the right operand are convertible toT
, e.g. for thestd::vector<int> v
above,v = { 1, 2, 3 }
will replace the container's contents with [1,2,3] and when the braced-init-list can be implicitly-converted to the operator's argument type, via a suitable constructor e.g.
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
将使用该临时参数作为参数调用.
On the last line of main
the braced-init-list will be implicitly-converted to a temporary A
then the assignment operator of B
will be called with that temporary as its argument.
这篇关于我们可以在哪里使用列表初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:我们可以在哪里使用列表初始化?


- 如何对自定义类的向量使用std::find()? 2022-11-07
- 与 int by int 相比,为什么执行 float by float 矩阵乘法更快? 2021-01-01
- C++ 协变模板 2021-01-01
- 近似搜索的工作原理 2021-01-01
- 从python回调到c++的选项 2022-11-16
- 使用/clr 时出现 LNK2022 错误 2022-01-01
- Stroustrup 的 Simple_window.h 2022-01-01
- STL 中有 dereference_iterator 吗? 2022-01-01
- 一起使用 MPI 和 OpenCV 时出现分段错误 2022-01-01
- 静态初始化顺序失败 2022-01-01