C++20 adds the “spaceship operator” <=> for three-way comparison, fundamentally changing the way we implement comparison. But there are a lot more changes: Comparison categories will give more structure, and the new operator rewriting rules will massively reduce boilerplate. And like most C++ features, there are a couple of caveats we need to be aware of.
This talk will cover all the changes and give guidelines on how to use them. It will be very practical, answering questions like: How do I write a comparison operator for my classes? How do I write it for a generic container? How should I implement algorithms to leverage the three-way comparison? How do I handle all the types written without <=>?
Whether you are writing concrete applications or generic library code, you will have the necessary knowledge to apply the new features. And even if you cannot use C++20 in the foreseeable future, you will have a deeper understanding on proper comparison design.
See Also
- Mathematics behind Comparison #1: Equality and Equivalence Relations
- Mathematics behind Comparison #2: Ordering Relations in Math
- Mathematics behind Comparison #3: Ordering Relations in C++
- Comparisons in C++20
Source Code
The synth_three_way()
helper described in the talk.
// I don't think, I can claim copyright over such a basic snippet.
// In case you need a license anyway:
// Copyright (C) 2019 Jonathan Müller
// Distributed under the Boost Software License, Version 1.0.
// (See copy at https://www.boost.org/LICENSE_1_0.txt)
#include <compare>
#include <type_traits>
struct synth_three_way_t
{
// might want to noexcept qualify
template <typename T, std::totally_ordered_with<T> U>
constexpr auto operator()(const T& lhs, const U& rhs) const
{
if constexpr (std::three_way_comparable_with<T, U>)
return lhs <=> rhs;
else
{
if (lhs == rhs)
return std::strong_ordering::equal;
else if (lhs < rhs)
return std::strong_ordering::less;
else
return std::strong_ordering::greater;
}
}
};
inline constexpr synth_three_way_t synth_three_way;
template <typename T, typename U = T>
using synth_three_way_category
= decltype(synth_three_way(std::declval<const T&>(),
std::declval<const U&>()));