Defaulting <=>
automatically gives ==, !=, <, >, <=, >=
for free
C++20 has a new "default comparison" feature setup so that defaulting <=>
gives all the others for free. I believe that this has been the major motivation behind the addition of operator<=>
.
Adapted from https://en.cppreference.com/w/cpp/language/default_comparisons:
main.cpp
#include <cassert>
#include <compare>
#include <set>
struct Point {
int x;
int y;
auto operator<=>(const Point&) const = default;
};
int main() {
Point pt1{1, 1}, pt2{1, 2};
// Just to show it Is enough for `std::set`.
std::set<Point> s;
s.insert(pt1);
// All of these are automatically defined for us!
assert(!(pt1 == pt2));
assert( (pt1 != pt2));
assert( (pt1 < pt2));
assert( (pt1 <= pt2));
assert(!(pt1 > pt2));
assert(!(pt1 >= pt2));
}
compile and run:
sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
An equivalent more explicit version of the above would be:
struct Point {
int x;
int y;
auto operator<=>(const Point& other) const {
if (x < other.x) return -1;
if (x > other.x) return 1;
if (y < other.y) return -1;
if (y > other.y) return 1;
return 0;
}
bool operator==(const Point& other) const = default;
};
In this case, we need to explicitly set bool operator==(const Point& other) const = default;
because if operator<=>
is not defaulted (e.g. as given explicitly above), then operator==
is not automatically defaulted:
Per the rules for any operator<=>
overload, a defaulted <=>
overload will also allow the type to be compared with <
, <=
, >
, and >=
.
If operator<=>
is defaulted and operator==
is not declared at all, then operator==
is implicitly defaulted.
The above example uses the same algorithm as the default operator<=>
, as explained by cppreference as:
The default operator<=>
performs lexicographical comparison by successively comparing the base (left-to-right depth-first) and then non-static member (in declaration order) subobjects of T to compute <=>, recursively expanding array members (in order of increasing subscript), and stopping early when a not-equal result is found
Before C++20, you could not do something like operator== = default
, and defining one operator would not lead to the others being defined, e.g. the following fails to compile with -std=c++17
:
#include <cassert>
struct Point {
int x;
int y;
auto operator==(const Point& other) const {
return x == other.x && y == other.y;
};
};
int main() {
Point pt1{1, 1}, pt2{1, 2};
// Do some checks.
assert(!(pt1 == pt2));
assert( (pt1 != pt2));
}
with error:
main.cpp:16:18: error: no match for ‘operator!=’ (operand types are ‘Point’ and ‘Point’)
16 | assert( (pt1 != pt2));
| ~~~ ^~ ~~~
| | |
| Point Point
The above does compile under -std=c++20
however.
Related: Are any C++ operator overloads provided automatically based on others?
Tested on Ubuntu 20.04, GCC 10.2.0.