我试图理解这两种初始化方式之间的语义差异:
Foo foo{x};
Foo foo = {x};
Run Code Online (Sandbox Code Playgroud)
我很想知道以下情况的区别:
x是类型的Foo.Foo 有一个构造函数,它接受与x相同类型的参数.x不是类型,Foo但可以使用转换构造函数.x不是类型,Foo但可以使用explicit转换构造函数.根据差异我的意思是,在每种情况下:
T.C*_*.C. 21
Foo foo{x}; // 1
Foo foo = {x}; // 2
Run Code Online (Sandbox Code Playgroud)
1是直接列表初始化.2是复制列表初始化.
假设这Foo是一个类类型,那么在大多数情况下,它们在概念上或其他方面完全相同,除非在重载解析期间选择了显式构造函数,那么#2就是格式错误.特别是,与复制初始化不同,复制列表初始化在概念上不构造临时.
一个例外是何时x是Foo由其衍生的类型或类型.在这种情况下,#1等同于Foo foo(x);(即,直接初始化),#2等同于Foo foo = x;(即,复制初始化).微妙的区别在于,在这种情况下,#2的重载解析仅考虑非显式构造函数,而不是考虑所有构造函数,如果选择了显式构造函数则会变得格式不正确.*此异常由CWG issue 1467的解决方案添加,于去年11月通过.
*你必须为此写一些非常折磨的代码.例如:
struct X
{
X() = default;
explicit X(X&);
X(const X&);
};
int main() {
X x1;
X x2 = {x1}; // #1
X x3 = x1; // #2
}
Run Code Online (Sandbox Code Playgroud)
在CWG1467之前,第1行是错误的,因为重载分辨率选择X(X&),即explicit.在CWG1467之后,不考虑explicit构造函数X(X&),因此X(const X&)使用.请注意,第2行总是格式良好并且使用X(const X&).