Angelus Mortis
Angelus Mortis

Reputation: 1554

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?

Upvotes: 14

Views: 418

Answers (2)

Columbo
Columbo

Reputation: 61009

TL;DR: The difference is that in the first case, as opposed to the second, the user-defined conversion sequences (A -> char, A -> int) call the same conversion function (operator char). That enables us to break the tie via [over.ics.rank]/(3.3).


The best conversion operators for particular functions are selected by [over.match.best]/(1.4) (comparing the conversion sequences of their return types).

Hence the better conversion function for foo(int) is operator char followed by a promotion to int, as opposed to operator double followed by a floating point conversion.

Now consider both variants of the second overload:

  1. The best ICS to foo(char) is also via operator char (identity better than floating point conversion). Thus [over.ics.rank]/(3.3) is applicable:

    User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function […] and in either case the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.

    Hence the overall conversion to F2 is deemed better, and it is selected.

  2. The best ICS to foo(double) is via operator double. We end up with two conversion sequences employing distinct conversion functions; nothing really applies, and we just get an ambiguity.

Upvotes: 5

T.C.
T.C.

Reputation: 137414

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.

Upvotes: 6

Related Questions