Перейти к содержанию

Последнее обновление:2026-10-12

Оператор трёхстороннего сравнения <=> в C++20

Три вида упорядоченности

Оператор трёхстороннего сравнения <=> называют также «оператором космического корабля»; его возвращаемое значение имеет три вида упорядоченности — ниже подробно разберём это с точки зрения исходников gcc.

Примечание: для ленивых — примеры этого раздела уже выложены в сообществе (知识星球).

Использование: <=>

#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;
}

Вывод:

St16partial_ordering
St15strong_ordering
  1. 1.1 <=> 2.2: это сравнение двух чисел с плавающей точкой. Для плавающих чисел стандартная библиотека возвращает std::partial_ordering, поскольку наличие NaN не делает их сравнение строгим полным порядком. std::partial_ordering допускает результаты <, >, == или unordered.

Мы можем посмотреть статические переменные в коде gcc, чтобы понять, что именно означает partial_ordering — меньше, больше, равно или неупорядоченно:

static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;

Если же выполнить принудительное преобразование, получим ошибку:

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`: это сравнение двух целых чисел. Для целых чисел стандартная библиотека возвращает `std::strong_ordering`, поскольку сравнение целых — строгий полный порядок без неопределённых случаев. `std::strong_ordering` возвращает только `<`, `>` или `==`.

Аналогично можно использовать следующие 4 статических члена.

static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;

Поэтому типом c1 является std::partial_ordering, а типом c2 — std::strong_ordering, что и объясняет, почему выведенные типы различаются.

Помимо partial_ordering и strong_ordering, <=> может возвращать и weak_ordering, со следующими статическими членами:

static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;

equal и equivalent

В приведённых выше трёх ordering для равенства появилось два термина: equal и equivalent — в чём же между ними разница?

Обратимся напрямую к cppreference: различий между ними нет. Однако std::strong_ordering — единственная категория, определяющая равенство (equality). Все остальные категории определяют лишь эквивалентность. Это как раз подтверждается приведёнными выше статическими членами: у string_ordering их два, у остальных есть только equivalent.

Если сравнение даёт между сравниваемыми объектами строгий порядок, то эквивалентность и равенство совпадают. Тому есть два слова лишь потому, что для других видов упорядоченности это не так. Слабый и частичный порядки вообще не имеют равенства; они предоставляют только эквивалентность.

Эквивалентность означает, что два объекта могут сравниваться как равные. Равенство означает нечто большее: если объекты сравниваются как равные, один может быть заменён другим в любом const-использовании — пока a == b истинно, выполняется и свойство f(a) == f(b), где f обозначает функцию, читающую только сравнительно значимое состояние, доступное через публичные const-члены параметров. Если сравнение типа допускает равенство (что требуется для строгого порядка), оно допускает и эквивалентность. Поэтому для сравнения со строгим порядком они совпадают.

https://en.cppreference.com/w/cpp/utility/compare/strong_ordering

Зачем нужен оператор трёхстороннего сравнения?

Оператор трёхстороннего сравнения (<=>) позволяет определить отношение порядка двух значений за одну операцию, тогда как традиционным операторам сравнения потребовалось бы несколько сравнений.

Ограничения традиционных операторов сравнения:

  • Если a == b ложно, вы не можете узнать, a < b это или a > b.
  • Если a != b истинно, вы не можете узнать, a < b это или a > b.
  • Если a < b ложно, вы не можете узнать, a == b это или a > b.
  • Если a > b ложно, вы не можете узнать, a == b это или a < b.
  • Если a <= b истинно, вы не можете узнать, a == b это или a < b.
  • Если a >= b истинно, вы не можете узнать, a == b это или a > b.

Эти ограничения показывают, что традиционные операторы сравнения не могут за один раз определить полное отношение двух значений — для получения исчерпывающего результата требуется несколько сравнений.

На этом раздел закончен

Похожие темы

Комментарии