Given the following program:
#include <iostream>
#include <string>
using namespace std;
struct GenericType{
operator string(){
return "Hello World";
}
operator int(){
return 111;
}
operator double(){
return 123.4;
}
};
int main(){
int i = GenericType();
string s = GenericType();
double d = GenericType();
cout << i << s << d << endl;
i = GenericType();
s = GenericType(); //This is the troublesome line
d = GenericType();
cout << i << s << d << endl;
}
It compiles on Visual Studio 11, but not clang or gcc. It is having trouble because it wants to implicitly convert from a GenericType
to an int
to a char
but it also could return a string
and so there is an ambiguity (operator=(char)
and operator=(string)
both match GenericType
).
The copy constructor is just fine, however.
My question is: How do I resolve this ambiguity without modifying the contents of main? What do I need to do to modify GenericType
to handle this situation?
I believe that gcc and clang are correct.
There are two operator=
overloads in play:
string& operator=(string const& str); // (1)
string& operator=(char ch); // (2)
Both of these operator=
overloads require a user-defined conversion from your argument of type GenericType
. (1) requires the use of the conversion to string
. (2) requires the use of the conversion to int
, followed by a standard conversion to char
.
The important thing is that both overloads require a user-defined conversion. To determine whether one of these conversions is better than the other, we can look to the overload resolution rules, specifically the following rule from C++11 §13.3.3.2/3 (reformatted for clarity):
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 or constructor or aggregate initialization and
the second standard conversion sequence of
U1
is better than the second standard conversion sequence ofU2
.
Note that an and joins the two parts of the rule, so both parts must be satisfied. The first part of the rule is not satisfied: the two user-defined conversion sequences use different user-defined conversion functions.
Therefore, neither conversion is better, and the call is ambiguous.
[I don't have a good suggestion on how to fix the problem without changing the definition of main()
. Implicit conversions are usually not a good idea; they are sometimes very useful, but more frequently they are likely to cause overload ambiguities or other weird overloading behavior.]
There was a gcc bug report in which this problem was described, and resolved as by design: compiler incorrectly diagnoses ambigous operator overload.