Why will std::rel_ops::operators be deprecated in C++20?
In C++20, you get three-way comparison (operator <=>
), which automatically "generates" default comparisons if provided:
struct A {
// You only need to implement a single operator.
std::strong_ordering operator<=>(const A&) const;
};
// Compiler generates 4 relational operators (you need to default the
// three-way comparison operator to get == and !=).
A to1, to2;
if (to1 > to2) { /* ... */ } // ok
if (to1 <= to2) { /* ... */ } // ok, single call to <=>
There are multiple advantages of the three-way comparison over std::rel_ops
, which is probably why std::rel_ops
operators are deprecated. On top of my head:
It is more versatile, since, depending on the return type of
operator<=>
(std::strong_ordering
,std::weak_ordering
, ...), only relevant operators are generated. See the<compare>
header for more information.You do not bring a bunch of templated operator overloads by doing
using namespace std::rel_ops
.You can ask the compiler to generate the three-way operator for you by defaulting it (
auto operator<=>(A const&) = default
) — This will basically generate a lexicographic comparison of base classes and non-static data members, plus it will deduce the right type of ordering if the return type isauto
.
What's the rationale behind?
rel_ops
was deprecated by Library Support for the Spaceship (Comparison) Operator. The paper doesn't list any motivation, but it does appear in the spaceship paper:
This subsumes namespace
std::rel_ops
, so we propose also removing (or deprecating)std::rel_ops
.
There are four reasons mentioned in the paper (including correctness and performance). But one big one not mentioned in either paper is that std::rel_ops
just... doesn't work. Rule of thumb is that operators are found using ADL. rel_ops
doesn't give you ADL-findable operators, it just declares unconstrained function templates like:
namespace std {
namespace rel_ops {
template< class T >
bool operator!=( const T& lhs, const T& rhs )
{
return !(lhs == rhs);
}
}
}
So using algorithms like:
struct X { ... };
bool operator<(X const&, X const&) { ... };
std::sort(values.begin(), values.end(), std::greater<>{});
Just doesn't work, unless you make sure to:
#include <utility>
using namespace std::rel_ops;
Fairly consistently everywhere as your first include to ensure that these operators are visible at the point of definition of every function template you could possibly call.
So operator<=>
is just strictly superior:
- It actually works.
- You only have to write one function (
<=>
) instead of two (==
and<
) - Typically, you actually have to write zero functions (
= default
) - Did I mention it actually works?
C++20 provides Three way comparison thus the unique ones will become deprecated.