我们知道T v(x);
叫做直接初始化, while T v = x;
叫做复制初始化,这意味着它将构建一个临时的T
from x
将被复制/移动到v
(这很可能被省略)。
对于列表初始化,标准根据上下文区分两种形式。T v{x};
叫做直接列表初始化 while T v = {x};
叫做复制列表初始化:
§8.5.4 [dcl.init.list] p1
[...]列表初始化可以发生在直接初始化或复制初始化中
上下文;直接初始化上下文中的列表初始化称为直接列表初始化复制初始化上下文中的列表初始化称为复制列表初始化. [...]
然而,整个标准中只有两个参考文献。对于直接列表初始化,在创建临时变量时会提到,例如T{x}
(§5.2.3/3
)。对于复制列表初始化,它适用于 return 语句中的表达式,例如return {x};
(§6.6.3/2
).
现在,下面的代码片段怎么样?
#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
定义为delete
d.然而,最新版本的 Clang 和 GCC 可以很好地编译上面的代码,经过一番挖掘(并找到上面的引用),这似乎是正确的行为。该标准仅定义了整个列表初始化的行为,除了上述几点之外,根本不区分两种形式。好吧,至少据我所知,无论如何。
因此,再次总结我的问题:
如果列表初始化(显然)做完全相同的事情,那么将列表初始化分为两种形式有什么用?
因为他们don't做完全相同的事情。如13.3.1.7[over.match.list]所述:
在复制列表初始化中,如果选择显式构造函数,则初始化格式错误。
简而言之,您只能在复制列表初始化上下文中使用隐式转换。
这是明确添加的,以使统一初始化不,嗯,统一。是的,我知道这听起来有多愚蠢,但请耐心听我说。
在2008,N2640 发布 (PDF) http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2640.pdf,看一下统一初始化的当前状态。它专门研究了直接初始化之间的区别(T{...}
)和复制初始化(T = {...}
).
总而言之,人们担心的是explicit
构造函数实际上将变得毫无意义。如果我有某种类型T
我希望能够从整数构造,但我不想隐式转换,我将构造函数标记为显式。
然后有人这样做:
T func()
{
return {1};
}
如果没有当前的措辞,这将称为我的explicit
构造函数。那么制作构造函数有什么好处呢explicit
如果没有太大变化呢?
按照目前的措辞,你至少需要直接使用名称:
T func()
{
return T{1};
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)