#include <iostream>
using namespace std;
struct CL2
{
CL2(){}
CL2(const CL2&){}
};
CL2 cl2;
struct CL1
{
CL1(){}
operator CL2&(){cout<<"operator CL2&"; return cl2;}
operator const CL2&(){cout<<"operator const CL2&"; return cl2;}
};
CL1 cl1;
int main()
{
CL1 cl1;
CL2 cl2 (cl1);
}
clang 和 gcc 都给出了模棱两可的转换运算符,但 Visual Studio 编译正常并打印“operator const CL2&”。根据标准,必须如何正确?
正如我所理解的,将 CL1 转换为 const CL2& 是在复制初始化上下文中(作为 cl2 对象直接初始化的一部分)。我看过 n4296 草案,[over.match.copy]:
假设“cv1 T”是被初始化对象的类型,T是类类型,候选函数的选择如下:
— T的转换构造函数(12.3.1)是候选函数。
— 当初始化表达式的类型是类类型“cv S”时,考虑 S 及其基类的非显式转换函数。初始化临时绑定到构造函数的第一个参数时,其中参数的类型为“对可能 cv 限定的 T”的引用,并且在直接初始化类型对象的上下文中使用单个参数调用构造函数“cv2 T”,还考虑了显式转换函数。那些没有隐藏在 S 中并产生其 cv 非限定版本与 T 相同类型或者是其派生类的类型是候选函数。返回“对 X 的引用”的转换函数根据引用的类型返回类型 X 的左值或 x 值,因此在选择候选函数的过程中被认为产生 X。
即两个转换运算符都被视为返回 CL2 和 const CL2(不仅仅是没有 const 的 CL2),还有待解决,哪种转换更好:CL2 -> const CL2& 或 const CL2 -> const CL2&。第二种情况似乎更合适。在这种情况下是否应该考虑更好的资格转换?或者两种情况都是身份转换?我在标准中找不到它