我试图理解这两种初始化方式之间的语义差异:
Foo foo{x};
Foo foo = {x};
我很想知道以下情况的区别:
x
的类型为Foo
。Foo
有一个构造函数,它接受与x。x
不属于Foo
类型,但可以使用转换构造函数。x
不属于Foo
类型,但可以使用explicit
转换构造函数。根据差异我的意思是,在每种情况下:
答案 0 :(得分:20)
Foo foo{x}; // 1
Foo foo = {x}; // 2
1是 direct-list-initialization 。 2是 copy-list-initialization 。
假设Foo
是类类型,那么在大多数情况下,它们在概念上或其他方面完全相同,除非在重载解析期间选择了显式构造函数,那么#2是不正确的。特别是,与复制初始化不同,复制列表初始化在概念上不构造临时。
一个例外是x
属于Foo
类型或从中派生的类型。在这种情况下,#1相当于Foo foo(x);
(即直接初始化),而#2相当于Foo foo = x;
(即复制初始化)。细微差别在于,在这种情况下,#2的重载解析只考虑非显式构造函数,而不是考虑所有构造函数,如果选择了显式构造函数则会变得格式不正确。*此异常由{{3的分辨率添加这是去年十一月通过的。
*你必须为此写一些非常折磨的代码。例如:
struct X
{
X() = default;
explicit X(X&);
X(const X&);
};
int main() {
X x1;
X x2 = {x1}; // #1
X x3 = x1; // #2
}
Pre-CWG1467,第1行格式不正确,因为重载决策选择X(X&)
,即explicit
。在CWG1467之后,explicit
构造函数X(X&)
未被考虑,因此使用了X(const X&)
。请注意,第2行始终格式正确,并使用X(const X&)
。