I've been combing through the internet to find an answer, but I couldn't find any. The only reasons given seems to be relevant for comparing with objects of different type (e.g. MyClass == int
). But the most common use case is comparing a class instance to another instance of the same class, not to any unrelated type.
In other words, I do understand the problems with:
struct A {
bool operator==(int b);
};
But I cannot find any good reason to not use member function in the most obvious use-case:
struct A {
bool operator==(const A&);
};
On the other hand, member overload seems to have a couple positive sides:
Is overloading operator==
as non-member function just a convention to keep it the same with possible overloads in other classes? Or are there any other reasons to make it non-member?
Overloading Binary Operators Suppose that we wish to overload the binary operator == to compare two Point objects. We could do it as a member function or non-member function. To overload as a member function, the declaration is as follows: class Point { public: bool operator==(const Point & rhs) const; // p1.
[13.6] Can I overload operator== so it lets me compare two char[] using a string comparison? No: at least one operand of any overloaded operator must be of some class type.
You can redefine or overload the function of most built-in operators in C++. These operators can be overloaded globally or on a class-by-class basis. Overloaded operators are implemented as functions and can be member functions or global functions.
You can overload any of these operators, which can be used to compare the objects of a class. Following example explains how a < operator can be overloaded and similar way you can overload other relational operators.
Well, in your question, you did forget to const
qualify the member function, and it would be harder to write bool operator==(A&, const A&);
by accident.
If you had an implicit constructor, a class with implicit conversion to A
or base class with an operator==
with higher priority, the member function wouldn't work if it was on the left, but would if it was on the right. Although most of the time implicit conversions are a bad idea, inheritance could reasonably lead to a problem.
struct A {
A(int); // Implicit constructor
A();
bool operator==(const A&) const;
};
struct B : A {
bool operator==(const B&) const;
};
void test() {
A a;
B b;
// 1 == a; // Doesn't work
a == 1;
// b == a; // Doesn't work; Picks `B::operator==(const B&) const;`
a == b; // Picks `A::operator==(const A&) const`, converting `b` to an `A&`.
// Equality is no longer symmetric as expected
}
In the future, with the C++20 operator<=>
, you will most likely always implement this as a member function (namely as auto operator<=>(const T&) const = default;
), so we know that this guideline may change.
The arguments for using non-member operator overload for symmetric operations are based on style and consistency. They are not very strong arguments 1. Non-member overloads are typically preferred because a weak argument is still a little bit better than no argument at all.
Your arguments for member operator overload don't seem to be any stronger. Consider following:
No need to befriend the function
On the other hand, if you use a non-member overload, then you don't have need to declare a member function. Is befriending the non-member somehow worse?
or to provide getters for members
There is no need for that if you befriend the overload.
It is always available to class users (although this might be the downside also)
It is unclear how this differs from the non-member overloads. Are they also not always available to the class users?
No problems with lookup (which seems to be common in our GoogleTests for some reason)
Are there lookup problems with non-member overloads? Could you demonstrate the problem with an example, and show how the problem is solved by using a member overload instead?
If it does solve the problem, then you can of course use that. Just because some guidelines recommend that you prefer one alternative as a rule of thumb, doesn't mean that is the only alternative to be used in all use cases.
1 Although, see answer https://stackoverflow.com/a/57927564/2079303 which is arguably stronger than just stylistic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With