带双花括号的向量初始化:std :: string vs int [英] Vector initialization with double curly braces: std::string vs int
问题描述
在此问题的答案中:初始化vector< string>带有双花括号的
它显示为
vector<string> v = {{"a", "b"}};
将调用 std :: vector
构造函数使用一个元素的 initializer_list
。因此,向量中的第一个(也是唯一一个)元素将由 { a, b}
构造。这会导致不确定的行为,但这超出了这里的重点。
will call the std::vector
constructor with an initializer_list
with one element. So the first (and only) element in the vector will be constructed from {"a", "b"}
. This leads to undefined behavior, but that is beyond the point here.
我发现的是
std::vector<int> v = {{2, 3}};
将调用 std :: vector
构造函数两个元素的初始化程序列表
。
为什么这种行为方式不同的原因?
Why is the reason for this difference in behavior?
推荐答案
类类型的列表初始化的规则基本上是:首先,仅考虑进行重载解析std :: initializer_list
构造函数,然后,如有必要,对所有构造函数进行重载解析(这是 [over.match.list] )。
The rules for list initialization of class types are basically: first, do overload resolution only considering std::initializer_list
constructors and then, if necessary, do overload resolution on all the constructors (this is [over.match.list]).
初始化 std :: initializer_list<时; E>
从初始化列表中,就好像我们从 N 元素中实现了 const E [N]
在初始化列表中(来自 [dcl.init.list] / 5
When initializing a std::initializer_list<E>
from an initializer list, it's as if we materialized a const E[N]
from the N elements in the initializer list (from [dcl.init.list]/5).
对于 vector< string> v = {{ a, b}};
我们首先尝试 initializer_list< string>
构造函数,这将涉及尝试初始化1个常量字符串
的数组,其中一个 string
初始化为 { a, b}
。这是可行的,因为 string
的迭代器对构造函数,所以我们最终得到了一个包含单个字符串的向量(UB为UB,因为我们违反该字符串构造函数的先决条件)。
For vector<string> v = {{"a", "b"}};
we first try the initializer_list<string>
constructor, which would involve trying to initialize an array of 1 const string
, with the one string
initialized from {"a", "b"}
. This is viable because of the iterator-pair constructor of string
, so we end up with a vector containing one single string (which is UB because we violate the preconditions of that string constructor). This is the easy case.
对于 vector< int> v = {{2,3}};
,我们首先尝试 initializer_list< int>
构造函数,这将涉及尝试初始化1的数组 const int
,其中一个 int
初始化为 {2,3}
。这是不可行的。
For vector<int> v = {{2, 3}};
we first try the initializer_list<int>
constructor, which would involve trying to initialize an array of 1 const int
, with the one int
initialized from {2, 3}
. This is not viable.
因此,我们考虑所有 vector
构造函数,重做重载解析。现在,我们得到了两个可行的构造函数:
So then, we redo overload resolution considering all the vector
constructors. Now, we get two viable constructors:
-
vector(vector&&)
,因为当我们递归地初始化参数时,初始化列表将为{2,3}
-我们将尝试使用该数组初始化2个const int
,这是可行的。 -
vector(std :: initializer_list< int>)
。这次不是来自普通的列表初始化世界,而是直接从相同的{2,3}
initializer_list >初始化程序列表,出于相同的原因也是可行的。
vector(vector&& )
, because when we recursively initialize the parameter there, the initializer list would be{2, 3}
- with which we would try to initialize an array of 2const int
, which is viable.vector(std::initializer_list<int> )
, again. This time not from the normal list-initialization world but just direct-initializing theinitializer_list
from the same{2, 3}
initializer list, which is viable for the same reasons.
要选择哪个构造函数,我们必须进入 [over.ics.list] ,其中 vector(vector&&)
构造函数是用户定义的转换顺序,但 vector(initializer_list< int>)
构造函数为 identity ,因此是首选。
To pick which constructor, we have to go to into [over.ics.list], where the vector(vector&& )
constructor is a user-defined conversion sequence but the vector(initializer_list<int> )
constructor is identity, so it's preferred.
为了完整起见, vector(vector const&)
为也是可行的,但是出于其他原因,我们宁愿将move构造函数比于copy构造函数。
For completeness, vector(vector const&)
is also viable, but we'd prefer the move constructor to the copy constructor for other reasons.
这篇关于带双花括号的向量初始化:std :: string vs int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!