【发布时间】:2013-09-04 23:03:09
【问题描述】:
我有以下代码sn-p:
struct T {
T(const T&) = default;
T(const S &);
};
struct S {
operator T();
};
int main() {
S s;
T t = s; // copy-initialization of class type
return 0;
}
我的问题是为什么编译器更喜欢 S::operator T() 来初始化 t 而不是报告初始化不明确的错误。在我看来,会发生以下情况(如果我错了,请纠正我):
- t 使用 S 类型的左值进行复制初始化
- S 不是 T,S 也不是 T 的子类,所以 S 和 T 不相关
- 由于变量 t 是复制初始化的,并且类型 S 和 T 不相关,编译器会尝试找到用户定义的转换序列来进行初始化。
- 重载解析负责选择最佳的用户定义转换,可以是T的转换构造函数,也可以是S的转换函数
- 参数 s 的构造函数 T::T(const S&) 的隐式转换序列是恒等转换,因为左值 s 可以直接绑定到此左值引用
- 参数 s 的转换函数 S::operator T() 的隐式转换序列也是恒等转换,因为隐式对象参数是 S&
构造函数和转换函数都返回一个 T 类型的纯右值,可用于直接初始化变量 t。这意味着两个自定义转换序列的第二个标准转换序列是恒等转换。
这意味着两个用户定义的转换序列同样好。还是有什么特殊的规则偏爱转换函数?
我正在阅读 c++11 标准中的以下规则:
表单中发生的初始化 Tx = 一个; 以及在参数传递、函数返回、抛出异常 (15.1)、处理异常 (15.3) 和聚合成员初始化 (8.5.1) 中称为复制初始化。
初始化器的语义如下...如果目标类型是(可能是 cv-qualified)类类型:如果初始化是直接初始化,或者如果是复制初始化,其中 cv-unqualified 源类型的版本与目标类是同一类或派生类, 构造函数被考虑...... 否则(即,对于剩余的复制初始化情况),可以从源类型转换到目标类型或(当使用转换函数时)到其派生类的用户定义转换序列被枚举,如 13.3 中所述。 1.4,通过重载决议选择最好的(13.3)
如果用户定义的转换序列U1包含相同的用户定义的转换函数或构造函数,并且U1的第二个标准转换序列优于第二个标准转换序列,则用户定义的转换序列U1是比另一个用户定义的转换序列U2更好的转换序列U2
也许我在做出错误的假设。我希望你能帮助我!
【问题讨论】: