{x}和'= {x}'初始化之间有什么区别?

Mus*_*afa 17 c++ c++11

我试图理解这两种初始化方式之间的语义差异:

Foo foo{x};
Foo foo = {x};
Run Code Online (Sandbox Code Playgroud)

我很想知道以下情况的区别:

  1. x是类型的Foo.
  2. Foo 有一个构造函数,它接受与x相同类型的参数.
  3. x不是类型,Foo但可以使用转换构造函数.
  4. x不是类型,Foo但可以使用explicit转换构造函数.

根据差异我的意思是,在每种情况下:

  1. 从概念上讲,调用哪些构造函数?
  2. 哪些构造函数调用通常由编译器优化?
  3. 是否允许隐式转换?

T.C*_*.C. 21

Foo foo{x};    // 1

Foo foo = {x}; // 2
Run Code Online (Sandbox Code Playgroud)

1是直接列表初始化.2是复制列表初始化.

假设这Foo是一个类类型,那么在大多数情况下,它们在概念上或其他方面完全相同,除非在重载解析期间选择了显式构造函数,那么#2就是格式错误.特别是,与复制初始化不同,复制列表初始化在概念上不构造临时.

一个例外是何时xFoo由其衍生的类型或类型.在这种情况下,#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&).

  • @black如果您阅读了该问题,您可以看到OP询问了4个不同的案例,每个案例有3个问题.我无法理解为什么TC应该跳过篮球来做出不必要的臃肿的答案,因为他到目前为止已经足够了. (3认同)