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转换[class.conv]
1类对象的类型转换可以由构造函数指定
并通过转换功能。这些转换称为用户定义
转换并用于隐式类型转换(第4节)
初始化(8.5),以及显式类型转换(5.4,5.2.9)。
2用户定义的转换仅在明确无误的情况下应用
(10.2,12.3.2)。转换遵守访问控制规则(第11条)。
模糊度解决(3.4)后应用访问控制。
3 [注:
有关在函数调用中使用转换的讨论,请参见13.3
以及下面的例子。 - 尾注]
4最多一个用户定义的
隐式应用转换(构造函数或转换函数)
到一个单一的价值。
没有多步骤 用户自定义 隐式转换。
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最多一个用户定义的
隐式应用转换(构造函数或转换函数)
到一个单一的价值。
由于这种结构完全合法
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)。