c++ - std::initializer_list 变体

标签 c++ syntax c++11 initialization initializer-list

以下三种用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/

相关文章:

c# - 如何在 c# 中的内存中直接一个接一个地创建结构?

c++ - 模板类的模板嵌套类作为完全专用函数的参数

c++ - 使用 std::adopt_lock 选项构造后,std::lock_guard 是否释放互斥锁?

c++ - 学习c++11智能指针,它不会让我像指针一样使用隐式转换吗?

javascript - Codecademy howOld 语法错误 else if

c - (void)strcpy(somevariable1, somevariable2) 正确吗?

c++ - 使用递归查找数组中的第 k 个最小元素?

c++ - 为什么使用存储在虚方法表中的地址调用虚函数会返回垃圾?

c++ - 不确定性的来源

mysql - 显示按月份名称排序的两个日期字段中的数据