当我们枚举构造函数并检查它们的可行性时 - 即是否存在隐式转换序列 - 对于移动构造函数,[dcl.init.ref]/5落入最后一个要点(5.2.2),即由核心问题1604和1571(按此顺序)修改。
这些决议的底线是
如果T1
orT2
是一个类类型并且与T1
不相关T2
,则使用T1
用户定义的转换(8.6、13.3.1.4、 13.3.1.5);如果相应的非参考复制初始化格式错误,则程序格式错误。调用转换函数的结果,如针对非引用复制初始化所描述的,然后用于直接初始化引用。
第一部分只是导致选择转换运算符。所以,根据粗体部分,我们使用const Y
直接初始化Y&&
。同样,我们一直失败,直到最后一个要点,由于(5.2.2.3)而失败:
If T1
is reference-related to T2
:
— cv1应与cv2具有相同的 cv-qualification 或大于 cv-qualification ;和
然而,这不再属于我们最初的重载决议,它只看到转换运算符将用于直接初始化引用。在您的示例中,重载解析选择移动构造函数,因为[over.ics.rank]/(3.2.5),然后上面的段落使程序格式错误。这是一个缺陷,已作为核心问题 2077归档。一个明智的解决方案是在重载决议期间丢弃移动构造函数。
所有这些都对您的修复有意义:删除const
将防止失败,因为这些类型现在是引用兼容的,并且删除移动构造函数会留下具有 const 引用的复制构造函数(即也可以工作)。最后,当我们写Y y = x;
, 而不是 [dcl.init]/(17.6.2) 时,应用 (17.6.3) ;
否则(即,对于剩余的复制初始化情况),可以从源类型转换到目标类型或(当使用转换函数时)到其派生类的用户定义转换序列被枚举,如 13.3 中所述。 1.4,最好的一个是通过重载决议(13.3)选择的。[...]。该调用用于根据上述规则直接初始化作为复制初始化目标的对象。
即初始化实际上与Y y(x.operator const Y());
成功相同,因为移动构造函数不可行(Y&& y = const Y
失败得足够浅)并且选择了复制构造函数。