Xeo*_*Xeo 37 c++ language-lawyer c++11 list-initialization
我们知道这T v(x);
被称为直接初始化,而T v = x;
被称为复制初始化,这意味着它将构造一个临时T
的x
,将被复制/移入v
(很可能被省略).
对于列表初始化,标准根据上下文区分两种形式.T v{x};
称为直接列表初始化,T v = {x};
称为复制列表初始化:
§8.5.4 [dcl.init.list] p1
[...]列表初始化可以在直接初始化或复制初始化上下文中进行; 直接初始化上下文中的列表初始化称为直接列表初始化,复制初始化上下文中的列表初始化称为复制列表初始化.[...]
但是,整个标准中只有两个引用.对于直接列表初始化,在创建像T{x}
(§5.2.3/3
)这样的临时表时会提到它.对于copy-list-initialization,它用于返回语句中的表达式,如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};
}
Run Code Online (Sandbox Code Playgroud)
通常,从X x = expr;
模式中,我们期望代码无法编译,因为移动构造函数X
定义为delete
d.但是,最新版本的Clang和GCC编译上面的代码就好了,经过挖掘(并找到上面的引用)后,这似乎是正确的行为.标准只定义了整个列表初始化的行为,除了上面提到的点之外,根本不区分这两种形式.好吧,至少我可以看到,无论如何.
那么,再次总结一下我的问题:
如果它们(显然)执行完全相同的事情,将列表初始化拆分为两种形式有什么用?
Nic*_*las 33
因为他们没有做同样的事情.如13.3.1.7 [over.match.list]中所述:
在copy-list-initialization中,如果选择了显式构造函数,则初始化是错误的.
简而言之,您只能在复制列表初始化上下文中使用隐式转换.
这是明确添加的,以使统一初始化不是,嗯,统一.是的,我知道这听起来多么愚蠢,但请耐心等待.
2008年,N2640发布(PDF),看看统一初始化的当前状态.它特别注意了direct initialization(T{...}
)和copy-initialization(T = {...}
)之间的区别.
总而言之,关注的是explicit
构造者实际上会变得毫无意义.如果我有一些T
我希望能够从整数构造的类型,但我不想隐式转换,我将构造函数标记为显式.
然后有人这样做:
T func()
{
return {1};
}
Run Code Online (Sandbox Code Playgroud)
如果没有当前的措辞,这将调用我的explicit
构造函数.那么explicit
如果构造函数没有太大变化,它有什么用呢?
使用当前的措辞,您至少需要直接使用该名称:
T func()
{
return T{1};
}
Run Code Online (Sandbox Code Playgroud)