【发布时间】:2012-11-07 19:14:06
【问题描述】:
我们知道T v(x);被称为direct-initialization,而T v = x;被称为copy-initialization,意思是它会构造一个临时的T从x 将被复制/移动到 v(很可能被省略)。
对于列表初始化,标准根据上下文区分两种形式。 T v{x}; 被称为 direct-list-initialization 而T v = {x}; 被称为 copy-list-initialization:
§8.5.4 [dcl.init.list] p1
[...] 列表初始化可以发生在直接初始化或复制初始化中 上下文;直接初始化上下文中的列表初始化称为direct-list-initialization,复制初始化上下文中的列表初始化称为copy-list-initialization。 [...]
但是,在整个标准中,每个参考文献只有两个。对于直接列表初始化,在创建像 T{x} (§5.2.3/3) 这样的临时对象时会提到它。对于复制列表初始化,它用于返回语句中的表达式,如return {x}; (§6.6.3/2)。
现在,下面的sn-p呢?
#include <initializer_list>
struct X{
X(X const&) = delete; // no copy
X(X&&) = delete; // no move
X(std::initializer_list<int>){} // only list-init from 'int's
};
int main(){
X x = {42};
}
通常,从X x = expr; 模式,我们预计代码编译失败,因为X 的移动构造函数定义为deleted。但是,最新版本的 Clang 和 GCC 可以很好地编译上面的代码,并且在挖掘了一下(并找到上面的引用)之后,这似乎是正确的行为。该标准只定义了整个列表初始化的行为,除了上述几点之外,根本不区分这两种形式。好吧,至少据我所知。
所以,再次总结一下我的问题:
如果它们(显然)做完全相同的事情,那么将列表初始化分成两种形式有什么用?
【问题讨论】:
-
如果你创建了第三个构造函数
explicit,它会停止工作吗? -
直接初始化和复制初始化的区别在 8.5 #16 中定义。直接初始化只考虑构造函数,而复制初始化考虑用户定义的转换序列。因此,使 ctor 显式将导致编译器错误。
标签: c++ c++11 language-lawyer list-initialization