[cfe-dev] error: use of overloaded operator '==' is ambiguous

Douglas Gregor dgregor at apple.com
Fri Jul 30 13:41:52 PDT 2010

On Jul 29, 2010, at 6:58 PM, John McCall wrote:

> On Jul 29, 2010, at 6:03 PM, Shawn Erickson wrote:
>> Sorry for the longish code example attached to this email but I am
>> trying to understand if clang is being overly pedantic in this
>> situation. Also please let me know if I should just file defects
>> instead of posting to this mailing list (unsure if this is a clang
>> problem or not).
> Filing bugs is generally nicer.
>> It seems like clang should be ignoring the private bool operators when
>> searching for a candidate.
> Access doesn't affect visibility in C++:  first you decide which operator you want,
> then you decide whether you can access it.
>> I assume the built-in ones would be
>> ignored/not listed if the only direct candidate was int32_t.
> If by 'direct candidate' you mean a member function candidate, you don't
> consider member operators unless the left operand is of class type.  In this
> case, Status::eNo has type ResultCodeConst, i.e. int64_t.  Neither ADL not
> unqualified lookup find any user-defined operators, so the only possibilities
> are the builtin candidates.
> That said, I think the builtin candidate at (int64_t, int32_t) should be viable;
> Doug, thoughts?

Clang is doing the right thing here (and EDG agrees with Clang that this code is ill-formed due to an ambiguity), but it takes a bit of standards-reading to see why. Let's go with Eli's reduction of the issue, here, although the issue is the same:

struct A
   operator int();
   operator bool();

int main(int argc, char** argv) {
   if (1000 == A()) {

And we'll consider two built-in candidates (of the many required by C++ 13.6 [over.built]p12):

	operator==(int, int)
	operator==(int, float)

For both candidates, the first argument is trivially an exact match. It's the second argument, of type A, that is interesting.

For operator==(int, int), we perform overload resolution to find a conversion from A to int. Per C++ [over.match.conv]p1, we consider all of the conversion functions in A as candidates. Both conversion functions work, so we perform overload resolution to see which conversion function is better. C++ 13.3.3 [over.match.best]p1 tells us that, since we're performing initialization by user-defined conversion, we can compare the last conversion sequences for the two conversion functions:

	for operator int(), we have an exact match
	for operator bool(), we have an integral promotion

An exact match is better than an integral promotion, so we pick the operator int() conversion sequence. Therefore, the conversion sequence for the second argument to operator==(int, int) is identity->user-defined operator int()->identity.

For operator==(int, float), we again perform overload resolution using the two conversion functions in A, but this time we're converting to float. The last conversion sequences for the two conversion functions are:

	for operator int(), we have an integral-to-floating conversion
	for operator bool(), we have an integral-to-floating conversion

The two integral-to-floating conversion functions are indistinguishable, so the conversion sequence for the second argument to operator==(int, float) is the ambiguous conversion sequence (C++ [over.best.ics]p10).

Now, we go to see which of operator==(int, int) or operator==(int, float) is better. The conversion sequences for the first argument are simple: both are exact matches, neither is better than the other. For the second argument, we're comparing a user-defined conversion sequence (using A::operator int()) against the ambiguous conversion sequence. Per C++ [over.best.ics]p10, "the ambiguous conversion sequence is treated as a user-defined sequence that is indistinguishable from any other user-defined conversion sequence", meaning that we can't order these two. Hence, there is an ambiguity and the code is ill-formed.

I don't know why GCC doesn't catch this ambiguity. My hunch is that it isn't including all of the built-in operator candidates required by the standard, since I've seen such problems with GCC before.

To fix the original code, you can add overloaded operator=='s such as

	bool operator==(int32_t, ResultCodeClass);
	bool operator==(ResultCodeClass, int32_t);

	- Doug

More information about the cfe-dev mailing list