Reputation: 1817
struct BaseA {
auto operator==(const BaseA& other) const {return other.a == a;}
int a;
};
struct B {
int b;
};
struct A: public BaseA {
auto operator==(const B& other) const {return other.b == a;}
};
int main() {
A a{10};
a == a;
return 0;
}
It won't compile:
error: no match for ‘operator==’ (operand types are ‘A’ and ‘A’)
note: candidate: ‘auto A::operator==(const B&) const’
note: no known conversion for argument 1 from ‘A’ to ‘const B&’
Doesn't list BaseA::operator==
as a candidate.
However, if I comment out A::operator==
method, it compiles.
Because of that I thought comparison operators get some special treatment, (sometimes generated for the child class, sometimes not, like those out of rule-of-five), but after a quick search turns out not the case.
Some rules of operator overloading, then?
Upvotes: 1
Views: 148
Reputation: 1817
I found a fix, without writing out using
for each comparison operator I add in the child class:
Make the operator non-member and pull it out to the enclosing scope of A
(in this example the global scope):
auto operator==(const A&, const B&)
If you want to access private members of A
or the protected of its base class, you can make the operator a friend of A
. (Same for B
.)
The hiding (meaning that if the name is found in a scope, it won't look in next ones, those the lookup algorithm is going to consider in the next step) won't stop this from working because for operators, two separate lookups, subsequently unioned, are performed:
For an operator used in expression (e.g., operator+ used in a+b) two separate lookups are performed: for the non-member operator overloads and for the member operator overloads (for the operators where both forms are permitted). Those sets are then merged with the built-in operator overloads on equal grounds.
-- cppreference
Thus the non-member operator==
in global namespace won't prevent searching for BaseA::operator==
, which is searched for in the member operator lookup, starting in A
(but there's no operator==
now), so moving on the the next scope, the base class BaseA
.
This way of fixing it is important for me, because I use a strong types library and I just wanted to add just one operator for the strong type, wrapping an integer. I'm using the library ti avoid writing out the boilerplate myself, and yet every time I would add an operator, I would have to use
the one in the library.
Upvotes: 0
Reputation: 123094
Nothing special about operators here, you'd get the similar error with:
struct BaseA {
auto foo(const BaseA& other) const {return other.a == a;}
int a;
};
struct B {
int b;
};
struct A: public BaseA {
auto foo(const B& other) const {return other.b == a;}
};
int main() {
A a{10};
a.foo(a);
}
Compiler finds a foo
in A
and stops there. If you want to have both you need to explicitly pull it in scope:
struct A: public BaseA {
auto foo(const B& other) const {return other.b == a;}
using BaseA::foo;
};
Upvotes: 2