How to overload operator ==? - c++

I have class A
how to overload operator == to perform
A a,b,c;
if (a==b==c) {}
Could anyone help me?

Very short answer: NO!
Slightly longer answer: Don't try this.
Explanation: Every C++ programmer is used to have the comparison operator return a bool or something convertible to bool. Just because it's natural to type things like if (a==b).
So if the expression a==b returns a bool x, then a==b==c would mean comparing x with c. Which makes no sense at all. Even if you get it to compile, e.g. comparing ints that way, it would not yield the result you expect.
So, while there technically I can think of a solution to what you seem to want (compare if all three are equal), the right thing to do is how it is always done in C++: logically chain binary comparisons:
if (a==b && b==c) {}
for the ones who wonder about the "technical doable but oh so ugly" solution:
(DON'T DO THIS IN REAL WORLD USE! You should get fired if you do.)
template <class T>
struct multiCompareProxy {
bool b;
T const& t;
explicit operator bool() const {return b;}
multiCompareProxy operator==(T const& rhs) {
return {b && t.equals(rhs), t};
}
};
template <class T>
multiCompareProxy<T> operator==(T const& lhs, T const& rhs) {
return {lhs.equals(rhs), lhs};
}
A class now just has to overload the euqals method for this to work: Example

If for whatever reason you really wanted to do this, you'd need a proxy object like so:
struct A {};
struct Proxy {};
Proxy operator==(const A& a, const A& b) {
return {};
}
bool operator==(const Proxy& p, const A& b) {
return true;
}
bool operator==(const A& a, const Proxy& p) {
return true;
}
#include <iostream>
int main() {
A a, b, c;
if(a == b == c) {
std::cout << "Bad.\n";
}
}
But don't do this. Use (a == b) && (a == c) like everyone else.

It can be done, and it's very occasionally useful as a kind of domain-specific language (DSL) for matching the notation expected by non-C++-programmers, but it should be studiously avoided for other uses as it'll confound (and annoy) programmers working on the code if this is used willy-nilly.
class A
{
// ...
bool equals(const A& rhs) const { return ... }
struct X
{
X(const A& a, bool b) : a_(a), b_(b) { }
X& operator==(const A& rhs) const { b_ &= a_.equals(rhs); return *this; }
explicit operator bool() const { return b_; }
// remove explicit pre C++11 / consider making it operator void*() ...
const A& a_;
mutable bool b_;
};
X A::operator==(const A& rhs) const
{
return X(*this, equals(rhs));
}
};
(You might prefer standalone functions if you have implicit constructors).
The same kind of proxy-using hackery allows all manner of unexpected notations like 3 < x < 9 and x == a1 || a2 || a3... again, avoid them unless it'll make a huge difference to the maintainers of the code where they'll be used (and ideally that code will have very clear boundaries from the other C++ code in your system).
As an example of good uses of such techniques, consider the boost spirit library and it's unusual use of a lot of operators to provide something approximating BNF notation....

You cannot (minus the possibility of an ugly hack) overload operator==(...) to work as you have specified.
If you think about what it would do a == b would become either true or false (a bool), then you would have (<bool> == c) left. The proper way to do what you are looking to do would be some form of (a==b) && (b==c).
There are times when you can overload an operator to work as you describe, but it would have to return the same type that it takes. An example would be:
class A
{
A& operator+=(A const& rhs)
{
// operator logic
return *this;
}
}
This case works because with a += b += c, you would perform (b += c) which would return an A&, which the remaining a.operator+=(...) accepts as an argument.

bool operator==(T const & a, T const & b) {
return /*boolean expr*/
}
if you have a class you can do:
class MyClass {
public:
bool operator==(T const & rhs) const {
return /*boolean expr*/
}
}
And don't use == twice in a row, you can't, do:
a == b && b == c

I would write:
bool operator==(const A& lhs, const A& rhs){ /* do actual comparison */ }
And use it twice with and operation.

Related

C++17 operator==() and operator!=() code fails with C++20

I've got the following sample code:
#include <assert.h>
struct Base
{
bool operator==(const Base& rhs) const
{
return this->equalTo(rhs);
}
virtual bool equalTo(const Base& rhs) const = 0;
};
inline bool operator!=(const Base& lhs, const Base& rhs)
{
return !(lhs == rhs);
}
struct A : public Base
{
int value = 0;
bool operator==(const A& rhs) const
{
return (value == rhs.value);
}
virtual bool equalTo(const Base& rhs) const
{
auto a = dynamic_cast<const A*>(&rhs);
return (a != nullptr) ? *this == *a : false;
}
};
class A_1 : public A
{
virtual bool equalTo(const Base& rhs) const
{
auto a_1 = dynamic_cast<const A_1*>(&rhs);
return (a_1 != nullptr) ? *this == *a_1 : false;
}
};
int main()
{
A_1 a_1;
a_1.value = 1;
// Make sure different types aren't equal
A a;
a.value = 1;
assert(a_1 != a);
}
When I compile with C++17, everything is fine (no assert, as desired). Building the same code with C++20 causes the assert to fire.
How can I get this existing code to work when compiling with C++20? If I crank up the warnings, with C++20, I get 'operator !=': unreferenced inline function has been removed; I suspect this is all somehow related to operator<=>().
Is this really a known/desired breaking change from C++17 to C++20?
In C++17, the line
assert(a_1 != a);
Invokes operator!=(const Base&, const Base&), because of course, it's the only candidate. That then invokes a_1->equalTo(a), which tries to downcast a to an A_1, which in your logic gives you false. So a_1 != a evaluates as true.
In C++20, we now additionally consider rewritten candidates in terms of ==. So now we have three candidates:
Base::operator==(const Base&) const (rewritten)
A::operator==(const A&) const (rewritten)
bool operator!=(const Base&, const Base&)
Of these, (2) is the best candidate, since it's a better match for the two parameters. So a_1 != a evaluates as !((const A&)a_1 == a), which gives you a different answer.
However, your operators are fundamentally broken. Even in C++17, we had the scenario that a_1 != a evaluates as true while a != a_1 evaluates as false. This is basically the inherent problem of trying to do dynamic equality like this: this->equalTo(rhs) and rhs.equalTo(*this) might actually do different things. So this issue is less of a C++20 comparisons issue and more of a fundamental design issue.

Is it possible not to inherit from boost::operators, but still use it?

According to boost documentation - proper usage of boost::operators is to derive from it:
class A : boost::operators<A>
{
public:
bool operator < (const A&) const { return false; }
};
Now, I can use > and <= and >= because all of these operators can be implemented with <, see code snippet from boost:
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
And finally less_than_comparable1 is one of boost::operators base class.
PROBLEM:
But adding such inheritance is not always convenient. E.g. this inheritance means I have to add constructor(s) to some structs, otherwise all old code, such as A{1} stops compiling:
struct A : boost::operators<A>
{
A() = default;
A(int a, int b = 0) : a(a), b(b) {}
int a;
int b;
};
bool operator < (const A&, const A&);
I tried several ways: inner class, static members of boost::operators<A> but it seems that only inheritance works.
I accept an answer that shows the way how to use boost::operators without inheritance.
I can also accept an answer, that explains why this inheritance is needed.
Ok, let's simplify a little this example, why I need inheritance in this very example below to get operator > from operator <?
template <typename A>
struct GtOperator
{
friend bool operator > (const A& l, const A& r)
{
return r < l;
}
};
struct A : private GtOperator<A>
{
bool operator < (const A&) const
{
return false;
}
};
int main() {
if (A{} > A{})
{
return -1;
}
}
Nothing else seems to work, e.g. this way does not work:
struct A
{
GtOperator<A> dummy;
bool operator < (const A&) const
{
return false;
}
};
Is it possible not to inherit from boost::operators, but still use it?
No, basically. It's intended to be inherited from. The reason it works is because argument-dependent lookup will only look for friend functions and function templates in associated classes ([basic.lookup.argdep]/4) - which are going to be A and A's base classes. If boost::operators<A> isn't a base class of A, its friend functions won't be found by name lookup.
Even with new aggregate initialization rules in C++17, A{1,2} would break because you'd have to write A{{},1,2}.
Your best bet is probably to write a macro that functions as a mixin that effectively accomplishes the same thing. So the ordering ones would be:
#define LESS_THAN_COMPARABLE(T) \
friend bool operator>(const T& x, const T& y) { return y < x; } \
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
class A
{
public:
bool operator < (const A&) const { return false; }
LESS_THAN_COMPARABLE(A)
};
Yes, that kind of sucks. (Also these could be defined as non-member functions as well, just drop the friend and put the macro invocation outside of the class).
The other alternative, besides adding constructors and writing macros, is to hope that <=> comes to fruition and then wait a few years to be able to use it.

Select templated operator implementation

Suppose we have an operator/ on custom class:
struct my_class {
uint64_t value;
}
template<class T>
constexpr T operator/(const my_class& a, const my_class& b)
{
return static_cast<T>(a.value) / static_cast<T>(b.value);
}
How can one select a / b (where a and b are of my_class type) to return int or double, for example?
You could with a bit of template magic and conversion operators. You can first define a simple wrapper for your expression:
struct DivideMyClass {
DivideMyClass(const MyClass& lhs_, const MyClass& rhs_) : lhs{lhs_}, rhs_{rhs} {}
template<typename T>
operator T () const {
return static_cast<T>(lhs.value) / static_cast<T>(rhs.value);
}
private:
const MyClass& lhs;
const MyClass& rhs;
};
Then, overloading the operator can be done like this:
constexpr DivideMyClass operator/(const my_class& a, const my_class& b)
{
return DivideMyClass{a, b};
}
Then your code will look like this:
double d = MyClass{21} / MyClass{5}; // will be equal to 4.2
Why this solution is bad
The language is not overloading division by the return type. You code will confuse other thinking there's a bug. If you use this method extensively, you will end up in an alomost unreadable code.
Another thing, the conversion is done implicitely, and there's nothing that says if there really was a conversion done in the operator on call site.
You will prevent the AAA idom (Almost Always use Auto). auto may break your code, and it's a bad thing.
Techniques like this should be use for template expression and stuff like that. Using that for simple division will confuse other.
Can I select based on type of variable accepting the result? I.e. int
result = a/b returns int, but double result = a/b returns double?
If you are hell-bent on doing this you can, but it's complicated and I wouldn't recommend it. You have to careful weight the benefits vs the complexity introduced. You can do this via lazy evaluation:
struct X {
int value;
};
struct X_op_proxy {
const X& lhs;
const X& rhs;
template <class T>
operator T() const { return static_cast<T>(lhs.value) / static_cast<T>(rhs.value); }
};
auto operator/(const X& lhs, const X& rhs) -> X_op_proxy
{
return {lhs, rhs};
}
int main()
{
X x1{11}, x2{2};
int i = x1 / x2;
cout << i << endl;
float f = x1 / x2;
cout << f << endl;
}
This is the minimum so you can figure out what this technique is about. You can adapt it and grow it to your needs.
To choose a specific operator template, you must call it as a function:
auto result = operator/<double>(my_class{4}, my_class{2});
// result is 2.0

Practical reason for defining operator!=

The following code will fail to compile under GCC because it does define operator== but does not define operator!=.
struct A {
unsigned int m_i;
bool operator == (const A& rhs) const { return m_i == rhs.m_i; }
};
bool f(const A& lhs, const A& rhs) { return lhs != rhs; }
Obviously it wants either
bool operator != (const A& rhs) const { return !(operator==(rhs)); }
or
bool operator != (const A& rhs) const { return m_i != rhs.m_i; }
Common wisdom seems to be that this is because !operator== adds an instruction and so is less efficient. This leads some programmers to dutifully write out their complex != expression in full, and over the years I've fixed a number of bugs resulting from mismatched operators.
Is this coercion to write both operators a case of premature/legacy optimization, or is there a good, solid, practical reason to do this code-doubling that I'm just somehow missing ?
I would say absent some overwhelming evidence to the contrary, it's purely premature optimization (not even legacy--I doubt there was ever a good reason for it, at least in anything approaching a C++ time-frame).
For what it's worth, ยง20.2.1 of the C++ standard defines a number of overloads in <utility> that will give you a != based on operator== and a >, >=, <= all based on operator<.
Why not use this:
bool f(const A& lhs, const A& rhs) { return !(lhs == rhs); }

Quick and dirty operator!=

In my classes I often write a quick operator!= by returning !(*this == rhs), e.g.:
class Foo
{
private:
int n_;
std::string str_;
public:
...
bool operator==(const Foo& rhs) const
{
return n_ == rhs.n_ && str_ == rhs.str_;
}
bool operator!=(const Foo& rhs) const
{
return !(*this == rhs);
}
};
I can't see any obvious problems with doing this but thought I'd ask if anyone knows of any.
I believe that's the preferred method of implementing operator!= so that you don't repeat yourself, and you have a guaranteed correct relationship with operator==.
Defining operator!= as !operator== is just fine
For getting these trivial equivalent operators easily defined, I always use Boost.Operators.
The case with only operator== and operator!= (i.e. using equality_comparable<>) doesn't gain very much.
But when you need less and greater than too, or some combination of operator+, operator* etc. this becomes very convenient.
An example for your case would read
class Foo : private boost::equality_comparable< Foo >
{
private:
int n_;
std::string str_;
public:
...
bool operator==(const Foo& rhs) const
{
return n_ == rhs.n_ && str_ == rhs.str_;
}
};
No, that's absolutely fine - I do exactly the same.