使用转换运算符复制初始化
Copy initialization with conversion operator
中有代码
struct A
{
operator int() { return 12;}
};
struct B
{
B(int) {}
};
int main()
{
....
A a;
B b0 = 12;
// B b1 = a; //< error: conversion from 'A' to non-scalar type 'B' requested
B b2{a}; // < identical, calling A::operator int(), then B::B(int)
B b3 = {a}; // <
auto b4 = B{a}; // <
}
现在的问题是
- 对于 b2,直接初始化如何工作?可以直接初始化调用转换运算符吗?
- 为什么 b1 的复制初始化失败?隐式A应该转换为int,B的构造函数可以被调用。
- b3 也是复制初始化,但它有效。为什么会这样?
这很简单:隐式转换(对于用户定义的类型)在 C++ 中不是 可传递的 属性。也就是说,虽然 A
可转换为 int
,而 int
可转换为 B
,但 而不是 本身意味着A
可转换为 B
。没有从 A
到 B
的有效隐式转换序列,因此 A
不能转换为 B
。
复制初始化需要初始化表达式的类型和被初始化的类型之间的隐式转换。由于 A
无法转换为 B
,因此 b1
无法编译。
任何时候你看到 {}
作为初始化的一部分,这意味着它所应用的对象将经历某种形式的列表初始化,这是一个不同于其他形式的过程初始化。
b2
不执行"direct initialization"。它直接执行 list 初始化,这是列表初始化的两种形式之一。在这种情况下,列表初始化的规则最终归结为对 B
的构造函数集使用重载决策。有一个 B
的构造函数,可以用 A
调用,因为该调用可以通过 A
到 int
.
的隐式转换发生
b3
不是 "copy initialization";是拷贝list初始化,跟"copy initialization"完全没有关系。 Copy-list-initialization 与 direct-list-initialization 完全相同,只有两个例外,两者都不适用于这种情况。所以它和 b2
.
做同样的事情
struct A
{
operator int() { return 12;}
};
struct B
{
B(int) {}
};
int main()
{
....
A a;
B b0 = 12;
// B b1 = a; //< error: conversion from 'A' to non-scalar type 'B' requested
B b2{a}; // < identical, calling A::operator int(), then B::B(int)
B b3 = {a}; // <
auto b4 = B{a}; // <
}
现在的问题是
- 对于 b2,直接初始化如何工作?可以直接初始化调用转换运算符吗?
- 为什么 b1 的复制初始化失败?隐式A应该转换为int,B的构造函数可以被调用。
- b3 也是复制初始化,但它有效。为什么会这样?
这很简单:隐式转换(对于用户定义的类型)在 C++ 中不是 可传递的 属性。也就是说,虽然 A
可转换为 int
,而 int
可转换为 B
,但 而不是 本身意味着A
可转换为 B
。没有从 A
到 B
的有效隐式转换序列,因此 A
不能转换为 B
。
复制初始化需要初始化表达式的类型和被初始化的类型之间的隐式转换。由于 A
无法转换为 B
,因此 b1
无法编译。
任何时候你看到 {}
作为初始化的一部分,这意味着它所应用的对象将经历某种形式的列表初始化,这是一个不同于其他形式的过程初始化。
b2
不执行"direct initialization"。它直接执行 list 初始化,这是列表初始化的两种形式之一。在这种情况下,列表初始化的规则最终归结为对 B
的构造函数集使用重载决策。有一个 B
的构造函数,可以用 A
调用,因为该调用可以通过 A
到 int
.
b3
不是 "copy initialization";是拷贝list初始化,跟"copy initialization"完全没有关系。 Copy-list-initialization 与 direct-list-initialization 完全相同,只有两个例外,两者都不适用于这种情况。所以它和 b2
.