CodeNebula
C++20coreadvanced

std::partial_ordering (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Comparison result type for partial ordering (e.g., floating-point with NaN).

Real-World Scenario

Compare measurements with NaN in a scientific application.

Quick Snippet

snippet.cpp
#include <compare> std::partial_ordering result = 1.0 <=> std::numeric_limits<double>::quiet_NaN();

Full Example

partial_ordering.cpp
// CodeNebula - C++20 Example: Partial Ordering
// Compile: g++ -std=c++20 -Wall -Wextra -o example partial_ordering.cpp

// Demonstrates std::partial_ordering for types where some values are
// incomparable, such as floating-point NaN values and set containment.

#include <iostream>
#include <compare>
#include <cmath>
#include <set>

// ------------------------------------------------------------------
// 1. Floating-point comparison naturally yields partial_ordering
// ------------------------------------------------------------------
void compare_doubles(double a, double b) {
    auto result = a <=> b;
    std::cout << "  " << a << " <=> " << b << ": ";
    if (result == std::partial_ordering::less) std::cout << "less";
    else if (result == std::partial_ordering::equivalent) std::cout << "equivalent";
    else if (result == std::partial_ordering::greater) std::cout << "greater";
    else if (result == std::partial_ordering::unordered) std::cout << "unordered";
    std::cout << std::endl;
}

// ------------------------------------------------------------------
// 2. Custom type with partial_ordering: subset comparison
// ------------------------------------------------------------------
struct IntSet {
    std::set<int> data;

    // A is "less" if it is a strict subset of B
    // A is "equivalent" if they have the same elements
    // A is "greater" if B is a strict subset of A
    // Otherwise, they are unordered (neither is a subset)
    std::partial_ordering operator<=>(const IntSet& other) const {
        bool a_sub_b = std::includes(other.data.begin(), other.data.end(),
                                     data.begin(), data.end());
        bool b_sub_a = std::includes(data.begin(), data.end(),
                                     other.data.begin(), other.data.end());

        if (a_sub_b && b_sub_a) return std::partial_ordering::equivalent;
        if (a_sub_b)            return std::partial_ordering::less;
        if (b_sub_a)            return std::partial_ordering::greater;
        return std::partial_ordering::unordered;
    }

    bool operator==(const IntSet& other) const {
        return data == other.data;
    }
};

void print_set(const IntSet& s) {
    std::cout << "{";
    bool first = true;
    for (int v : s.data) {
        if (!first) std::cout << ",";
        std::cout << v;
        first = false;
    }
    std::cout << "}";
}

void compare_sets(const IntSet& a, const IntSet& b) {
    auto result = a <=> b;
    std::cout << "  ";
    print_set(a);
    std::cout << " <=> ";
    print_set(b);
    std::cout << ": ";
    if (result == std::partial_ordering::less) std::cout << "less (subset)";
    else if (result == std::partial_ordering::equivalent) std::cout << "equivalent";
    else if (result == std::partial_ordering::greater) std::cout << "greater (superset)";
    else if (result == std::partial_ordering::unordered) std::cout << "unordered";
    std::cout << std::endl;
}

int main()
{
    std::cout << "=== Float Partial Ordering ===" << std::endl;
    double nan = std::numeric_limits<double>::quiet_NaN();
    compare_doubles(1.0, 2.0);
    compare_doubles(3.0, 3.0);
    compare_doubles(5.0, 1.0);
    compare_doubles(nan, 1.0);
    compare_doubles(1.0, nan);
    compare_doubles(nan, nan);

    std::cout << "\n=== NaN Comparison Booleans ===" << std::endl;
    std::cout << "  NaN < 1.0?  " << (nan < 1.0) << std::endl;
    std::cout << "  NaN > 1.0?  " << (nan > 1.0) << std::endl;
    std::cout << "  NaN == 1.0? " << (nan == 1.0) << std::endl;
    std::cout << "  NaN == NaN? " << (nan == nan) << std::endl;

    std::cout << "\n=== Set Containment (Partial Ordering) ===" << std::endl;
    IntSet a{{1, 2}}, b{{1, 2, 3}}, c{{1, 2}}, d{{2, 3}};
    compare_sets(a, b);   // subset
    compare_sets(b, a);   // superset
    compare_sets(a, c);   // equivalent
    compare_sets(a, d);   // unordered (neither is subset)
    compare_sets(b, d);   // superset

    std::cout << "\n=== partial_ordering Result Values ===" << std::endl;
    std::cout << "  less < 0?        " << (std::partial_ordering::less < 0) << std::endl;
    std::cout << "  equivalent == 0? " << (std::partial_ordering::equivalent == 0) << std::endl;
    std::cout << "  greater > 0?     " << (std::partial_ordering::greater > 0) << std::endl;
    std::cout << "  unordered == 0?  " << (std::partial_ordering::unordered == 0) << std::endl;
    std::cout << "  unordered < 0?   " << (std::partial_ordering::unordered < 0) << std::endl;
    std::cout << "  unordered > 0?   " << (std::partial_ordering::unordered > 0) << std::endl;

    return 0;
}

/*
Expected output:

=== Float Partial Ordering ===
  1 <=> 2: less
  3 <=> 3: equivalent
  5 <=> 1: greater
  nan <=> 1: unordered
  1 <=> nan: unordered
  nan <=> nan: unordered

=== NaN Comparison Booleans ===
  NaN < 1.0?  0
  NaN > 1.0?  0
  NaN == 1.0? 0
  NaN == NaN? 0

=== Set Containment (Partial Ordering) ===
  {1,2} <=> {1,2,3}: less (subset)
  {1,2,3} <=> {1,2}: greater (superset)
  {1,2} <=> {1,2}: equivalent
  {1,2} <=> {2,3}: unordered
  {1,2,3} <=> {2,3}: greater (superset)

=== partial_ordering Result Values ===
  less < 0?        1
  equivalent == 0? 1
  greater > 0?     1
  unordered == 0?  0
  unordered < 0?   0
  unordered > 0?   0
*/
Run command
g++ -std=c++20 -Wall -Wextra -o example partial_ordering.cpp