[英]Vector initialization with double curly braces: std::string vs int
在回答这个问题时: 使用双花括号初始化vector <string>
它表明
vector<string> v = {{"a", "b"}};
将使用带有一个元素的initializer_list
调用std::vector
构造initializer_list
。 因此,向量中的第一个(也是唯一的)元素将由{"a", "b"}
。 这会导致未定义的行为,但这超出了这一点。
我发现的是
std::vector<int> v = {{2, 3}};
将使用两个元素的initializer_list
调用std::vector
构造initializer_list
。
为什么这种行为差异的原因?
行为的差异是由于默认参数。 std::vector
有这个c'tor:
vector( std::initializer_list<T> init,
const Allocator& alloc = Allocator() );
注意第二个参数。 {2, 3}
推导为std::initializer_list<int>
(不需要初始化器的转换)并且分配器是默认的。
类类型列表初始化的规则基本上是:首先,只考虑std::initializer_list
构造函数进行重载解析,然后在必要时对所有构造函数执行重载解析(这是[over.match.list] )。
当从初始化列表初始化std::initializer_list<E>
,就好像我们从初始化列表中的N个元素(来自[dcl.init.list] / 5 )中实现了一个const E[N]
。
对于vector<string> v = {{"a", "b"}};
我们首先尝试使用initializer_list<string>
构造函数,这将涉及尝试初始化1个const string
的数组,其中一个string
从{"a", "b"}
初始化的。 这是可行的,因为string
的迭代器对构造函数,所以我们最终得到一个包含一个单独字符串的向量(这是UB,因为我们违反了该字符串构造函数的前提条件)。 这是一个简单的案例。
对于vector<int> v = {{2, 3}};
我们首先尝试使用initializer_list<int>
构造函数,这将涉及尝试初始化1个const int
的数组,其中一个int
从{2, 3}
初始化。 这不可行 。
那么,考虑到所有的vector
构造函数,我们重做重载决策。 现在,我们得到两个可行的构造函数:
vector(vector&& )
,因为当我们递归初始化参数时,初始化列表将是{2, 3}
- 我们将尝试初始化2 const int
的数组,这是可行的。 vector(std::initializer_list<int> )
,再次。 这一次不是从正常列表初始化的世界,但只是直接初始化initializer_list
从同{2, 3}
初始化列表,这是可行出于同样的原因。 要选择哪个构造函数,我们必须进入[over.ics.list] ,其中vector(vector&& )
构造函数是用户定义的转换序列,但vector(initializer_list<int> )
构造函数是identity ,因此它是首选。
为了完整性, vector(vector const&)
也是可行的,但出于其他原因,我们更喜欢移动构造函数到复制构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.