Comments 10
Чёто очень странное, походит то ли на перевод, то ли на генерацию
вообще ничего не понимаю что тут имелось в виду, кто такой _ordering
Потом говорится о типах, которых вообще в стандарте не существует, какие то strong_equality, дальше упоминается, что их не существует (зачем тогда упоминать?)
Итак, правильный ответ:
если ваш тип просто агрегация других типов:
auto operator<=>(const my_type&) const = default;
компилятор сам разберётся
Если нужно написать своё, то если два "равных" с точки зрения оператора== значения полностью неразличимы для наблюдателя, то strong_ordering.
Если различимы (например какой то из филдов не участвует в сравнении, но логически является частью типа), то weak_ordering
Если иногда у вас вообще не получается как то логично сравнить 2 значения - partial_ordering
Всё верно, этот конкретный фрагмент — перевод, так как я прямо цитировал пропозал Consistent comparison (P0515). Абзацем ранее было написано: «а какой тип, собственно, должен возвращать наш operator<=>
, если мы реализуем его своими руками: std::strong_ordering
, std::weak_ordering
или std::partial_ordering»
.
Видимо, я был должен уточнить, что под «_ordering
» подразумевается «(strong/weak/partial)_ordering
». Соглашусь с тем, что информация про удаленные виды экволити оказалась лишней. Моей мотивацией было полностью сохранить оригинальные формулировки, так как я посчитал, что они достаточно интересны и полезны. Но теперь мне действительно кажется, что они лишь вносят неясность. Спасибо, я подкорректирую этот фрагмент статьи.
Ваш ответ несомненно правильный, но очень сжатый. Целью моей статьи был развернутый ответ на вопрос с приведением примеров.
Еще раз спасибо за фидбек!
Слабо упорядоченные тип
Слабо упорядоченные же типы отличаются от полностью упорядоченных типов тем, что их эквивалентные значения могут быть неразличимы.
может быть все-же "различимы"?
Кстати, чисто порассуждать. Если с упорядоченностью всё понятно - есть упорядоченные и есть неупорядоченные типы, то вот с эквивалентностью/различимостью... Да, можно сказать что "ABC" и "abc" эквивалентны при case-insensitive сравнении, но при этом различимы. А можно сказать что два объекта различимы если они у них разные адреса в памяти (кажется это то что делает оператор "идентичности" === в некоторых языках). Можно придумать огромное количество уровней эквивалентности. Например если целые части двух чисел double равны, то числа эквивалентны. Или если равны с точностью до десятых, с точностью до сотых и т.д. Но оператор сравнения единственный, и поэтому, если мы его переопределяем, мы выбираем какой-то конкретный критерий эквивалентности. А что тогда такое "различимость"? Двоичная эквивалентность? А зачем это нужно, если программист явно определил, какие объекты считать "равными"? Не нарушает ли это принцип инкапсуляции?
Оригинальный пропозал Consistent comparison (P0515) подразумевает под различимостью то, что хоть a == b
может быть true
, но какое-то f(a) == f(b)
при этом может быть и не true
, где f
«считывает только заметное для сравнения состояние, доступное с помощью public
const
членов».
Стандарт не навязывает, что такое различимость. Программист сам регулирует это под свои намерения.
Мне кажется, в примере с CaseInsensitiveString
можно сказать, что в целом все, что от нее требуется — это case insensitive сравнение. Но концептуально она должна давать нам возможность получить исходный string
. Он может нам для чего-то понадобиться. Так что у нас тут weak order, ибо мы можем выдумать удовлетворяющую критериям функцию f
, что f(a) != f(b)
при a == b
: bool f(C a, C b) { return a.str(); == b.str(); }
Является ли адрес в памяти «заметным для сравнения состоянием, доступным с помощью public const
членов»? Наверное, только в очень специфических случаях. И программист это явно регулирует.
Про всякие даблы. Допустим, у нас есть класс, представляющий какое-нибудь вещественное число (без всяких NaN
ов). Программист явно определил, какие объекты считать «равными» (допустим, равные с точностью до целого). И программист явно же определил, какие объекты считать различимыми, ограничивая публичный интерфейс. Он сделал возможность получить исходное число частью публичного интерфейса — тогда 1.2 и 1.5 различимы. А если же не сделал — то есть, пользователи, пользуясь публичным интерфейсом, никак не могут различить 1.2 и 1.5 — неразличимы.
Имхо, с инкапсуляцией всё ок.
А зачем weak_ordering может потребоваться на практике?
Я уже как-то приводил где-то здесь этот гипотетический пример. Предположим, у нас есть некий контейнер. Этот контейнер в своей специализации для элементов со strong ordering имеет полное право хранить вместо кучи одинаковых элементов всего один элемент со счетчиком его дубликатов (ведь элемент заявляет, что его дубликаты неразличимы), в то же время как в своей специализации для элементов с weak ordering он, очевидно, не имеет на это права - он должен хранить все якобы "равные" элементы.
UPD 04.02.2024 (13:54 MSK)
Обновлено введение: добавлено пояснение относительно функции f
и в общем более человеческое объяснение как strong_ordering
, так и weak_ordering
. Удалена бесполезная информация касательно так и не попавших в стандарт strong_equality
и weak_equality
.
Раздел про слабо упорядоченные типы стал подробнее: появилось детальное объяснение понятия «различимости».
Какой тип ordering должен возвращать мой operator<=> в C++?