Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The <=> operator, formally known as the three-way comparison operator (and colloquially as the “spaceship operator”), is a C++20 language feature that evaluates the relative order of two operands in a single expression. Instead of returning a boolean, it returns a comparison category object indicating whether the left operand is less than, equal to/equivalent to, or greater than the right operand.
#include <compare>

auto result = lhs <=> rhs;

Comparison Categories

The operator relies on types defined in the <compare> header. It does not return an integer; it returns one of three standard comparison category types, which dictate the mathematical properties of the comparison:
  1. std::strong_ordering: Represents a strict total ordering. If a <=> b == std::strong_ordering::equal, then a and b are indistinguishable and perfectly substitutable.
    • Valid values: less, equal, greater.
    • Typical for integral types (int, char, pointers).
  2. std::weak_ordering: Represents a weak total ordering. If a <=> b == std::weak_ordering::equivalent, a and b evaluate as equivalent for sorting purposes, but their underlying states may differ (e.g., case-insensitive string comparison).
    • Valid values: less, equivalent, greater.
  3. std::partial_ordering: Represents a partial ordering where some values may be incomparable.
    • Valid values: less, equivalent, greater, unordered.
    • Typical for floating-point types where NaN (Not a Number) cannot be ordered relative to other values.

Evaluation Mechanics

The result of the <=> operator is designed to be compared against literal 0. The compiler translates traditional relational operators into <=> expressions when the traditional operators are not explicitly defined. The spaceship operator is strictly used to rewrite the four relational operators:
  • a < b evaluates as (a <=> b) < 0
  • a > b evaluates as (a <=> b) > 0
  • a <= b evaluates as (a <=> b) <= 0
  • a >= b evaluates as (a <=> b) >= 0
Equality (==) and inequality (!=) are never rewritten to use operator<=>. They are resolved strictly using operator== (with operand reversal if necessary).

Defaulting the Operator

When explicitly defaulted inside a class definition, the compiler automatically generates the <=> operator using a lexicographical, member-wise comparison. It compares base classes (left-to-right) and non-static data members in their exact order of declaration.
struct Entity {
    int id;
    double threshold;

    // Instructs the compiler to generate a member-wise three-way comparison.
    // The return type 'auto' allows the compiler to deduce the weakest 
    // comparison category among the members (std::partial_ordering here, due to double).
    auto operator<=>(const Entity&) const = default;
};
Defaulting operator<=> implicitly declares and defaults operator== as well. The generated operator== performs direct member-wise equality checks; it does not evaluate (a <=> b) == 0. Consequently, a single = default declaration provides the class with all six relational operators (==, !=, <, <=, >, >=).

Custom Implementation

When writing a custom <=> operator, you must explicitly specify the return type or use auto to let the compiler deduce it based on the returned comparison category.
struct Wrapper {
    int value;

    // Custom implementation
    std::strong_ordering operator<=>(const Wrapper& rhs) const {
        if (value < rhs.value) return std::strong_ordering::less;
        if (value > rhs.value) return std::strong_ordering::greater;
        return std::strong_ordering::equal;
    }

    // Note: Providing a custom <=> does NOT implicitly generate ==.
    // You must explicitly default or implement operator==.
    bool operator==(const Wrapper&) const = default;
};

Operator Rewriting and Symmetry

The compiler performs expression rewriting to ensure symmetry. If an expression a < b is encountered and the left operand a does not have a matching < or <=> operator, the compiler will attempt to rewrite the expression as 0 < (b <=> a), reversing the operands and utilizing the right operand’s operator. This eliminates the need to write multiple overloads for heterogeneous comparisons (e.g., comparing a class with an int in both obj < 5 and 5 < obj orders). The same operand reversal mechanism applies to operator== for equality checks.
Master C++ with Deep Grasping Methodology!Learn More