One area in C++ where there is significant complexity and inconsistency is the way compilers handle ref-qualified implicit conversion functions. 

I believe that most C++ users who put ref-qualifiers on implicit conversion functions expect those ref-qualifiers to have the same effect in all situations. Probably few know that the ref-qualifiers will have different effects in different situations, as illustrated by the examples below. 

The following example compiles with gcc, clang, icc and msvc. 

------------------ 

struct S  

 

        operator int() const & { return 0; }  

        operator char() && { return 0; }  

};  

 

void foo(int) {}  

void foo(char) {}  

 

int main()  

 

        foo(S{}); //OK, calls 'void foo(char)'.  

 

 

----------------- 

In the above example, it is clear that the ref-qualifier on the conversion function 'operator char() &&' must be the reason why the compilers select the 'void foo(char)' overload. The outcome of overload resolution in this case is probably the outcome that most lay C++ users expect and find logical, including myself. 

By contrast, the following example produces an outcome that will probably surprise most C++ users who are not experts in the C++ standard. The code is rejected as ill-formed by all four compilers. 

----------------- 

enum A{}; 

enum B{}; 

 

struct S 

{ 

    operator A() const & { return A{}; } 

    operator B() && { return B{}; } 

}; 

 

void foo(A) {} 

void foo(B) {} 

 

int main() 

{ 

    foo(S{}); //error: ambiguous call to overloaded function 

} 

 

------------------- 

In the above example, my naïve expectation was that the compiler would select the second overload for the same reason as in the previous example, that is, the ref-qualifier on the conversion function 'operator B() &&'. This outcome was what I expected when I put the ref-qualifier '&&' on the second conversion function. 

The following example is accepted by icc and rejected by the three other compilers. 

------------------- 

 

struct S 

{ 

        int i = 0; 

        operator const int &() const & { return i; } 

        operator int &&() && { return static_cast<int &&>(i); } 

}; 

 

void foo(const int &) {} 

void foo(int &&) {} 

 

int main() 

{ 

        foo(S{}); 

 

 

------------------- 

I believe that only experts in the C++ standard will know why each of the above code samples should be accepted or rejected. From the perspective of a non-expert like myself, the different outcomes are confusing.

But is it really necessary to have different outcomes? From what I understand, it seems possible to make all of the above code samples compile and produce a similar outcome by making one change to the rules of ranking implicit conversion sequences in 12.2.4.3 [over.ics.rank]. The current rules disregard the ref-qualifiers on user-defined conversion functions. If two user-defined conversion sequences use two different user-defined conversion functions, neither of them will be ranked as better than the other. My proposal is to make the compiler rank as better the user-defined conversion function whose ref-qualifier is a closer match to the value of the expression being converted. For example, if two user-defined conversion functions can be used to convert a prvalue, then the one that is ref-qualified with '&&' ranks better than the one that is ref-qualified with 'const &.'