以下三种用std::initializer_list
初始化的区别是什么?
std::vector<int> a{ 2, 3, 5, 7};
std::vector<int> b( { 2, 3, 5, 7} );
std::vector<int> c = { 2, 3, 5, 7};
在上面的例子中,std::vector
只是一个占位符,但我对一般答案感兴趣。
最佳答案
让我们抽象出 std::vector
.并称之为T
.
T t{a, b, c};
T t = { a, b, c };
T t({a, b, c});
前两种形式是列表初始化(它们之间唯一的区别是如果T
是一个类,对于第二个explicit
构造函数是禁止调用的。如果一个是被调用,程序变成病式)。最后一种形式只是我们从 C++03 知道的普通直接初始化:
T t(arg);
出现一个{a, b, c}
as arg 表示构造函数调用的参数是一个大括号初始化列表。第三种形式没有列表初始化所具有的特殊处理。 T
必须 是一个类类型,即使花括号初始化列表只有一个参数。我很高兴we put clear rules在这种情况下发布 C++11 之前。
关于第三个调用的构造函数,让我们假设
struct T {
T(int);
T(std::initializer_list<int>);
};
T t({1});
由于直接初始化只是对重载构造函数的调用,我们可以将其转换为
void ctor(int);
void ctor(std::initializer_list<int>);
void ctor(T const&);
void ctor(T &&);
我们可以使用两个尾随函数,但如果我们选择这些函数,则需要用户定义的转换。初始化 T ref
参数,将使用列表初始化,因为这不是用括号直接初始化(因此参数初始化等同于 T ref t = { 1 }
)。前两个函数是完全匹配的。但是,标准规定在这种情况下,当一个函数转换为 std::initializer_list<T>
时而另一个没有,则前一个功能获胜。因此在这种情况下,第二个 ctor
会被使用。 请注意,在这种情况下,我们不会使用第一个初始化列表 ctors 进行两阶段重载决议 - 只有列表初始化会这样做。
对于前两个,我们将使用列表初始化,它会做上下文相关的事情。如果T
是一个数组,它会初始化一个数组。拿这个例子上课
struct T {
T(long);
T(std::initializer_list<int>);
};
T t = { 1L };
在这种情况下,我们执行两阶段过载解析。我们首先只考虑初始化列表构造函数并查看是否匹配,作为参数我们采用整个花括号初始化列表。第二个 ctor 匹配,所以我们选择它。我们将忽略第一个构造函数。如果我们没有初始化列表构造函数或者没有匹配项,我们将获取所有构造函数和初始化列表的元素
struct T {
T(long);
template<typename A = std::initializer_list<int>>
T(A);
};
T t = { 1L };
在这种情况下,我们选择第一个构造函数,因为 1L
无法转换为 std::initializer_list<int>
.
关于c++ - std::initializer_list 变体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13459057/