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
一起使用?
描述多步隐式转换的一般规则是什么?
答案 0 :(得分:13)
没有多步用户定义的隐式转换。
int -> bool -> A
是允许的,因为int->bool
转换不是用户定义的。
1类对象的类型转换可以由构造函数指定 并通过转换功能。这些转换称为用户定义 转换并用于隐式类型转换(第4节) 初始化(8.5),以及显式类型转换(5.4,5.2.9)。
2用户定义的转换仅在明确无误的情况下应用 (10.2,12.3.2)。转换遵守访问控制规则(第11条)。 模糊度解决(3.4)后应用访问控制。
3 [注: 有关在函数调用中使用转换的讨论,请参见13.3 以及下面的例子。 - 后注]
4最多一个用户定义的 隐式应用转换(构造函数或转换函数) 单个值。
答案 1 :(得分:1)
由于这种结构是完全合法的
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将初始化列表作为单个参数或初始化时传递 list只有一个元素,并且转换为某个类X或引用(可能是cv-qualified)X 考虑到X的构造函数的第一个参数,或者在所有情况下由 13.3.1.4 ,13.3.1.5或13.3.1.6考虑,仅 考虑标准转换序列和省略号转换序列。
在这种情况下,不考虑用户定义的转换(C - > B)。