C++ 0x统一初始化"奇怪"

Eva*_*ran 17 c++ uniform-initialization c++11

像许多人一样,我对C++ 0x感到非常兴奋.我尝试在新项目中学习和使用新功能,这样我就可以编写最好,最易于维护的代码.

不用说,我喜欢新初始化器背后的想法.所以我在看他们,这些对我有意义:

T x = { 1, 2, 3 }; // like a struct or native array
T x({1, 2, 3});    // copy construct something like an "object literal" in other languages... cool!
return {1, 2, 3};  // similar to above, but returning it, even cooler!
Run Code Online (Sandbox Code Playgroud)

对我来说没有意义的是:

T x{1, 2, 3};
Run Code Online (Sandbox Code Playgroud)

它只是感觉......很奇怪.我不确定人们想要使用哪种语法,这是模仿,它似乎并不"正确".

这种语法背后的设计/思想是什么?

它似乎有所作为的唯一例子是这样的:

std::vector<int> the_vec{4};
Run Code Online (Sandbox Code Playgroud)

它会调用初始化列表构造函数,但为什么不写这个呢:

std::vector<int> the_vec = {4};
Run Code Online (Sandbox Code Playgroud)

并做每个人都已经习惯的事情?

Jam*_*lis 26

这种语法背后的设计/思想是什么?

首先,大括号语法可以避免烦恼的解析:

T x(); // function declaration
T x{}; // value-initialized object of type 'T' named 'x'
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,最接近它的是,T x((T()));或者T x = T();两者都需要T具有可访问的复制构造函数.

  • @Evan:有一个原因叫做_uniform_ initialization.因为它无处不在.`{}`表示"初始化"; 这就是它背后的想法. (6认同)

Joh*_*itb 19

首先,你真的有两个变体:

T x = { 1, 2, 3 };
T x{1, 2, 3};
Run Code Online (Sandbox Code Playgroud)

这两个实际上是在进行相同的初始化,但是如果选择explicit构造函数则第一个是无效的.否则它们是相同的.第一个称为"复制列表初始化",第二个称为"直接列表初始化".

这个概念是带有=分配"复合值"的形式 - 一个由3个整数组成的值.它x用该值初始化.对于这样的初始化,explicit应该只允许非  构造函数.x{1, 2, 3}(没有等号)的概念是你用3个值初始化变量- 概念上不是复合值,而是你碰巧同时给出的3个单独的值.您可以说这是该术语最一般意义上的"构造函数调用".

你展示的另一个初始化实际上与上面两个完全不同:

T x({1, 2, 3});
Run Code Online (Sandbox Code Playgroud)

它只调用Twith 的constuctors {1, 2, 3}作为参数.它没有做任何奇特的事情,比如初始化数组如果T是数组或初始化struct成员if if T是聚合结构/类.如果T不是类,则该声明无效.但是如果T碰巧有一个复制或移动构造函数,那么它又可以使用该构造函数来构造临时T副本列表初始化并将复制/移动构造函数引用参数绑定到该临时.我相信你不会经常在真实的代码中使用这种形式.


所有这些都记录在初始化列表的委员会提案文件中.在这种情况下,您需要查看初始化列表 - 替代机制和基本原理,在"程序员的初始化类型视图"部分中:

我们观察到,了解复制初始化和直接初始化之间差异的专家程序员经常错误地认为前者效率低于后者.(实际上,当两个初始化都有意义时,它们同样有效.)

相反,我们发现以不同的方式思考这些事情更有用:

  • 通过调用构造函数构造("ctor-call")
  • 通过转移价值构建("转换")

(实际上,前者对应于"直接初始化",后者对应于"复制初始化",但标准的术语对程序员没有帮助.)

后来他们发现了

请注意,因为我们对待{ ... }in

X x = { ... };
Run Code Online (Sandbox Code Playgroud)

作为单个值,它不等同于

X x{ ... };
Run Code Online (Sandbox Code Playgroud)

其中{ ... }是构造函数调用的参数列表(我们强调它,因为它与N2531不同).

C++ 0x FDIS中规定的规则与该论文中提出的规则略有不同,但该论文中提出的基本原理在C++ 0x FDIS中保留并实现.