#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);
}
Both clang and gcc give ambiguous conversion operator, but Visual Studio compiles ok and prints "operator const CL2&". How must be right according to Standard?
As I undestand, conversion of CL1 to const CL2& is in copy-initialization context (as a part of a direct-initialization of cl2 object). I seen n4296 draft, [over.match.copy]:
Assuming that “cv1 T” is the type of the object being initialized, with T a class type, the candidate functions are selected as follows:
— The converting constructors (12.3.1) of T are candidate functions.
— When the type of the initializer expression is a class type “cv S”, the non-explicit conversion functions of S and its base classes are considered. When initializing a temporary to be bound to the first parameter of a constructor where the parameter is of type “reference to possibly cv-qualified T” and the constructor is called with a single argument in the context of direct-initialization of an object of type “cv2 T”, explicit conversion functions are also considered. Those that are not hidden within S and yield a type whose cv-unqualified version is the same type as T or is a derived class thereof are candidate functions. Conversion functions that return “reference to X” return lvalues or xvalues, depending on the type of reference, of type X and are therefore considered to yield X for this process of selecting candidate functions.
I.e. both of conversion operators are considered as return CL2 and const CL2 (not just CL2 without const) and it remains to solve, which conversion is better: CL2 -> const CL2& or const CL2 -> const CL2&. The second case seems more appropriate. Should a better qualification conversion considered in that context? Or both cases are Identity conversion? I couldn't find it in Standard
operator const CL2&() const { cout << "operator const CL2&"; return cl2; }
– DeiDei