简体   繁体   中英

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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM