c++ - 为什么 C++ 列表初始化也考虑常规构造函数?

标签 c++ standards uniform-initialization

在 C++ 中,当使用 initializer_list 语法初始化对象时,当没有其他列表初始化规则适用时,对象的常规构造函数也参与重载决策。 据我了解,以下代码调用 X::X(int)

class X { int a_; X(int a):a_(a) {} );

void foo() {
   X bar{3};
}

但我不明白,为什么在 initializer_lists 的上下文中也考虑了常规构造函数。我感觉现在很多程序员都写X{3}来调用构造函数而不是X(3)来调用构造函数。 我一点也不喜欢这种风格,因为它让我觉得对象没有常规构造函数。

initializer_list 语法也可以用来调用常规构造函数的原因是什么?现在有理由比常规的构造函数调用更喜欢这种语法吗?

最佳答案

本质上是一团糟。对于 C++11,它试图创建一种统一的方法来初始化对象,而不是其他必要的多种方法:

  • T v(args...);对于通常情况
  • T d = T();为基于堆栈的对象使用默认构造函数时
  • T m((iterator(x)), iterator());对抗Most Vexing Parse (注意第一个参数周围的额外括号)
  • T a = { /* some structured values */ };用于聚合初始化

取而代之的是统一初始化语法:

T u{ /* whatever */ };

目的是统一的初始化语法将在所有地方使用,旧的 stule 将过时。一切都很好,除了来自 std::initializer_list<S> 的初始化支持者意识到语法应该是这样的:

std::vector<int> vt({ 1, 2, 3 });
std::vector<int> vu{{ 1, 2, 3 }};

这被认为是 Not Acceptable ,并且统一的初始化语法被不可挽回地妥协以允许更好

std::vector<int> vx{ 1, 2, 3 };

这种混合的问题在于,现在有时不清楚实际含义,统一的初始化语法不再统一。在某些情况下它仍然是必要的(特别是在通用代码中对基于堆栈的对象进行值初始化)但它并不是在所有情况下都是正确的选择。例如,以下两个表示法本应表示同一事物,但实际上并非如此:

std::vector<int> v0(1, 2); // one element with value 2
std::vector<int> v1{1, 2}; // two elements: 1 and 2

tl;dr:初始化列表和统一初始化语法是两个独立的符号。可悲的是,它们发生了冲突。

关于c++ - 为什么 C++ 列表初始化也考虑常规构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48004905/

相关文章:

带有堆栈变量的 C++ 头文件

c++ - 是否可以在不创建项目的情况下在Visual Studio 2019中编译运行HelloWorld.cpp?

c++ - 使用 HowardHinnant C++ 日期解析持续时间

pthreads - pthreads 的官方标准是什么?

bash - Shell 脚本模板

c++ - ={} 和 {} 风格的初始化在 C++11 中是否相同?

c++ - 在 VS2012 静态库、控制台应用程序和 clr 程序上使用 cryptopp 出现链接错误

javascript - 我应该完全停止使用内联 JavaScript 吗?

c++ - 为什么采用 std::initializer_list 的构造函数不首选双花括号语法

c++ - std::allocator 中的直接初始化与统一初始化