Search code examples
c++overloadinglanguage-lawyeroverload-resolutionconversion-operator

Overload resolution with multiple functions and multiple conversion operators


Consider simple code :

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (char){}
int main() {
    foo(a);
}

Above code works fine, and as expected gcc, clang and VC++ chooses foo(char).

Now lets modify the code little bit :

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (double){} //parameter changed from char to double
int main() {
    foo(a);
}

Now this should have choose foo(double), but seems only VC++ is happy with the code while clang and gcc are unhappy with the above code.

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous
 foo(a);
     ^
main.cpp:8:6: note: candidate: void foo(int)
 void foo(int){}
      ^
main.cpp:9:6: note: candidate: void foo(double)
 void foo (double){} //parameter changed from char to double
      ^

Can anyone explain why above code fails? or is it bug?.

One more question: Do gcc and clang share code of overload resolution?


Solution

  • A -> char is A -> char.

    A -> int is A -> char -> int (because char to int is a promotion and so beats the double to int conversion).

    A -> double is A -> double.

    Two user-defined conversion sequences are only comparable if they involve the same user-defined conversion function. Thus, A -> char is a better conversion sequence than A -> int, so your first case is unambiguous. Neither A -> int nor A -> double is better than the other, so the second case is ambiguous.