I am coming up against a vexing conundrum in my code base. I can\'t quite tell why my code generates this error, but (for example) std::string does not.
cla
The error goes away if you declare the member + const as it should be.
class String {
public:
String(const char*str);
friend String operator+ ( const String& lval, const char *rval );
friend String operator+ ( const char *lval, const String& rval );
String operator+ ( const String& rval ) const; //<-- here
};
Not sure what's the reason, though. Perhaps it prefers binding arguments to const reference if possible, so the first overload is a better match for the left-hand value and the third overload has a better match for the right-hand value.
Better explanation. (Must have misread the problem a bit.)
printf(result);
Don't tell me your String has implicit conversion to const char*
... That's evil.
It is sufficient in this case just to define on operator+
:
String operator+(const String& lval, const String& rval);
Because you provide a constructor taking a char*
, a String
can be constructed from a char*
during the call to operator+
. For example:
String hello = "Hello, ";
const char* world = "world!";
String helloWorld = hello + world;
A temporary String
will be constructed with the contents of the char*
world
(because your constructor is not explicit), then the two String
objects will be passed to operator+
.
You've shown that basic_string
has implementations of operator+
corresponding to the second and third operators in your class String
. Does basic_string
also have an operator corresponding to your first operator [friend String operator+ ( const String& lval, const char *rval );
]?
What happens if you remove this operator?
The reason for the ambiguity is that one candidate function is better than another candidate function only if none of its parameters are a worse match than the parameters of the other. Consider your two functions:
friend String operator+(const String&, const char*); // (a)
String operator+(const String&); // (b)
You are calling operator+
with a String
and a const char*
.
The second argument, of type const char*
, clearly matches (a) better than (b). It is an exact match for (a), but a user-defined conversion is required for (b).
Therefore, in order for there to be an ambiguity, the first argument must match (b) better than (a).
The String
on the left-hand side of the call to operator+
is not const. Therefore, it matches (b), which is a non-const member function, better than (a), which takes a const String&
.
Therefore, any of the following solutions would remove the ambiguity:
operator+
to be a const member functionoperator+
to take a String&
instead of a const String&
operator+
with a const String on the left hand sideObviously, the first, also suggested by UncleBens, is the best way to go.
Template and non-template functions follow different rules. The template functions are selected on the actual parameter types, without any conversions being applied. In the case of the non-template (i.e. your code) an implicit conversion can be applied. Thus the templated stuff in basic_string is not ambiguous, but yours is.