Can someone explain the rules of casting, and when a conversion is ambiguous? I’m getting slightly confused by the following case, which gives different answers on MSVC++ (Visual Studio 2010) and gcc-4.3.4.
#include <string>
class myStr
{
std::string value;
public:
myStr(const char* val) : value(val) {}
operator const char*() const {return value.c_str();}
operator const std::string() const {return value;}
};
myStr byVal();
myStr& byRef();
const myStr& byConstRef();
int main(int, char**)
{
myStr foo("hello");
std::string test;
// All below conversions fail "ambiguous overload for 'operator='" in gcc
// Only the indicated coversions fail for MSVC++
test = foo; // MSVC++ error "'operator =' is ambiguous"
test = static_cast<std::string>(foo);
test = byVal(); // MSVC++ error "'operator =' is ambiguous"
test = static_cast<std::string>(byVal()); // MSVC++ error
// "'static_cast' : cannot convert from 'myStr' to 'std::string'"
test = byRef(); // MSVC++ error "'operator =' is ambiguous"
test = static_cast<std::string>(byRef());
test = byConstRef(); // MSVC++ error "'operator =' is ambiguous"
test = static_cast<std::string>(byConstRef());
return 0;
}
What rules govern which of those conversions is legal? And is there any compliant way to use unambiguously a class like myStr which defines casts to both const char* and const std::string?
The implicit conversions are all ambiguous, since
std::stringhas overloaded assignment operators taking bothconst std::string&andconst char*. This means that both of your conversion operators are equally good choices, hence the ambiguity:The ambiguities with
static_castare because you’re using the cast to create a temporarystd::stringobject. It’s equally valid to create that from either astd::stringor aconst char*, so again both of your conversion operators are considered.You can break the ambiguity by instead casting to a reference:
This will still create a temporary, since the conversion operator returns an object. However, that conversion is now implicit, and so can’t involve more than one user-defined conversion; therefore, it can only be done via your
operator std::string()and there is no ambiguity.You might also consider changing the conversion operator to return a
constreference, so that the unnecessary temporary can be avoided.