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

时间:2012-10-11 19:43:20

标签: c++ type-conversion implicit-conversion

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一起使用? 描述多步隐式转换的一般规则是什么?

2 个答案:

答案 0 :(得分:13)

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

int -> bool -> A

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

12.3转化[class.conv]

  

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)。