Reputation: 1554
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
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:
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 sequenceU2
if they contain the same user-defined conversion function […] and in either case the second standard conversion sequence ofU1
is better than the second standard conversion sequence ofU2
.
Hence the overall conversion to F2
is deemed better, and it is selected.
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
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