不允许对自定义类型进行多次隐式转换?

Multiple implicit conversions on custom types not allowed?

本文关键字:转换 自定义 类型 不允许      更新时间:2023-10-16
class C {
public:
C() { }
};
class B {
public:
B(C c) { }
B() { }
};
class A {
public:
A(bool b) { }
A(B b) { }
};
int main() {
A a1 = true; // bool -> A        is allowed
A a2 = B();  // B -> A           is allowed
A a3 = 7;    // int -> bool -> A is allowed
A a4 = C();  // C -> B -> A      isn't allowed
}

为什么我可以对bool使用两步隐式转换,但不能与C一起使用? 描述多步隐式转换的一般规则是什么?

没有多步骤用户定义的隐式转换。

int -> bool -> A

是允许的,因为int->bool转换不是用户定义的。

12.3 转换 [类.conv]

1 类对象的类型转换可以由构造函数指定 以及通过转换功能。这些转换称为用户定义 转换,用于隐式类型转换(第 4 条),用于 初始化 (8.5) 和显式类型转换 (5.4、5.2.9)。

2 用户定义的转换仅在明确的情况下应用 (10.2, 12.3.2).转换遵守访问控制规则(第 11 条)。 访问控制在歧义解决 (3.4) 之后应用。

3 [ 注: 有关在函数调用中使用转换的讨论,请参阅 13.3 以及下面的示例。—尾注 ]

4 最多一个用户定义 隐式应用转换(构造函数或转换函数) 到单个值。

由于这种结构是完全合法

A a4((C()));

问题是,你使用复制初始化。真的,你的例子等于

A a4((A(C()));

8.5/16

初始值设定项的语义如下所示。目标类型是对象或引用的类型 已初始化,源类型是初始值设定项表达式的类型。如果初始值设定项不是单个(可能 括号)表达式,则未定义源类型。

如果目标类型是(可能符合 cv 条件的)类类型:

— 否则(即,对于剩余的复制初始化情况),用户定义的转换序列 可以从源类型转换为目标类型或(当转换函数时) 用于)到其派生类,如13.3.1.4中所述进行枚举,最好的是 通过过载分辨率 (13.3) 选择。

13.3.1.4/1

在 8.5 中指定的条件下,作为类类型对象的复制初始化的一部分,用户定义的 可以调用转换来将初始值设定项表达式转换为正在初始化的对象的类型。

重载解析用于选择要调用的用户定义转换。假设"cv1 T"是 正在初始化的对象的类型,其中 T 是类类型,候选函数的选择如下: — T 的转换构造函数 (12.3.1) 是候选函数。

— 当初始值设定项表达式的类型是类类型"cv S"时,非显式转换函数 考虑 S 及其基类。

13.3.3.1/4

但是,当考虑构造函数或用户定义的转换函数的参数时,它是 在类的第二步中调用用于复制/移动临时时,通过 13.3.1.3 的候选 复制初始化,当将初始值设定项列表作为单个参数传递时或初始值设定项时,由 13.3.1.7 进行 列表只有一个元素,并且转换为某个类 X 或引用(可能符合 cv 条件)X 是 考虑用于 X 构造函数的第一个参数,或者在所有情况下仅考虑 13.3.1.4、13.3.1.5 或13.3.1.6考虑标准转换序列和省略号转换序列。

在这种情况下,不考虑用户定义的转换 (C> B)。