Last updated:2026-10-12
C++20 Three-Way Comparison Operator <=>¶
Three Orderings¶
The three-way comparison operator <=>, also known as the spaceship operator, has three possible ordering return values. Let's dig into it from the gcc source code's point of view.
Note: for the lazy version, the examples for this section have been updated in the Knowledge Planet.
Usage: <=>
#include <compare>
#include <iostream>
int main() {
auto c1 = 1.1 <=> 2.2;
auto c2 = -1 <=> 1;
std::cout << typeid(c1).name() << std::endl;
std::cout << typeid(c2).name() << std::endl;
}
Output:
1.1 <=> 2.2: this compares two floating-point numbers. For floating-point numbers, the standard library returnsstd::partial_ordering, because the existence of NaN values means the comparison between them is not a strict total order.std::partial_orderingallows the result to be<,>,==, orunordered.
We can use the static variables in the gcc code to see whether a partial_ordering is less, greater, equivalent, or unordered:
static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;
If we force a conversion, we get an error:
comp.cc:6:36: error: conversion from 'std::partial_ordering' to non-scalar type 'std::strong_ordering' requested
6 | std::strong_ordering c1 = 1.1 <=> 2.2;
2. `-1 <=> 1`: this compares two integers. For integers, the standard library returns `std::strong_ordering`, because integer comparison is a strict total order with no indeterminate cases. `std::strong_ordering` only ever returns `<`, `>`, or `==`.
Likewise, the following 4 static members can be used.
static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;
Therefore, the type of c1 is std::partial_ordering while the type of c2 is std::strong_ordering, which also explains why the printed types differ.
Besides partial_ordering and strong_ordering, <=> can also return weak_ordering, whose static members are:
static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;
equal vs equivalent¶
In the three orderings above, you can see that "equal" shows up in two forms: equal and equivalent. What is the difference between the two?
Going straight to cppreference: there is no difference between them. However, std::strong_ordering is the only category that defines equality; all the other categories define only equivalence. This matches the static members above — strong_ordering has two, while the others only have equivalent.
If a comparison induces a strong ordering between the items being compared, equivalence and equality are the same. The reason there are two words for it is that this is not the case for the other kinds of ordering. Weak and partial have no equality at all; they only provide equivalence.
Equivalence means two objects can compare equal. Equality means something stronger: if they compare equal, one can be substituted for the other in any const usage — as long as a == b is true, the property f(a) == f(b) holds, where f denotes a function that reads only comparison-relevant state accessible through the argument's public const members. If a type's comparison permits equality (which is what strong ordering requires), it also permits equivalence. So for strong-ordering comparisons, the two are the same.
https://en.cppreference.com/w/cpp/utility/compare/strong_ordering
Why Use the Three-Way Comparison Operator?¶
The three-way comparison operator (<=>) lets you determine the ordering relationship between two values in a single operation, whereas the traditional comparison operators need multiple comparisons.
Limitations of the traditional comparison operators:
- If
a == bis false, you cannot tell whethera < bora > b. - If
a != bis true, you cannot tell whethera < bora > b. - If
a < bis false, you cannot tell whethera == bora > b. - If
a > bis false, you cannot tell whethera == bora < b. - If
a <= bis true, you cannot tell whethera == bora < b. - If
a >= bis true, you cannot tell whethera == bora > b.
These limitations show that the traditional comparison operators cannot determine the complete relationship between two values in one go; multiple comparisons are needed to obtain the full result.
That's all for this section.
Related Topics¶
- Getting Started with C++20 Coroutines | C++那些事
- C++20 channel in Practice | C++那些事
- C++20 Concepts | C++那些事
- C++20 constexpr and the Comma Expression | C++那些事
- C++20 Byte Order (endian) | C++那些事
- C++20 Lambda Expressions (Part 1) | C++那些事
- C++20 Modules | C++那些事
- C++20 Ranges Library | C++那些事
- C++20 std::span Design and Pitfalls | C++那些事
- A Guide to C++20 New Features | C++那些事