Why does this code not compile ? I would have expected that the built-in unary operator& would have been selected, such that the ambiguity between the two binary operator& should not matter. If you comment out one of the binary operator&, the code compiles (with gcc 11.2) and the built-in unary operator& is selected.
struct A
{ int operator&(int) const { return 1; }
};
struct B
{ int operator&(int) const { return 2; }
};
struct C : A, B
{};
C* test(C& c)
{ return &c; } //error: request for member 'operator&' is ambiguous
CodePudding user response:
Problem is overload resolution. First function name should be matched and if abutting is found error should be reported. After that matching of arguments is performed. Here is an example with regular function: https://godbolt.org/z/nYfjdn1Td
As you can see ambiguity is reported for foo
on all compilers even although both foo
s have different number of arguments.
Same issue should pop up for operator&
so more like gcc is right here.
Overload resolution is a complex topic. Usually you do not have to think about it. Here is nice source which explains how complex this is.
If you wish to fix problem and have binary operator available for such code, you can do this:
struct C : A, B
{
using A::operator&;
using B::operator&;
};
This fixes problem with your test on all compilers.
of course ambiguity for instaceOfC & intValue
remains, but you can resolve it by doping one using
statement.
https://godbolt.org/z/ds3W4GYcT
CodePudding user response:
This is due to unqualified name lookup.
Initially, name lookup begins in the scope of class C
. No declarations of operator&
are found.
Then look up proceeds to base classes in turn. In each of A
and B
there is a different declaration with the name operator&
.
At this point the set of declarations found by name lookup is A::operator&
and B::operator&
. These are considered ambiguous at the name lookup stage so overload resolution, where the difference between unary and binary operator&
would be discovered, is never reached.
See the example at cppreference for unqualified name look up for more info.
If only one of A
or B
was inherited then the name lookup set wouldn't be member function name lookup set wouldn't be ambiguous. It would proceed to overload resolution an correctly deduce unary operator&
.
struct C : A, B
{
using A::operator&;
using B::operator&;
};
The scope of C
is searched before base classes so the ambiguous step is never reached.