Как стать автором
Обновить

Комментарии 10

Чёто очень странное, походит то ли на перевод, то ли на генерацию

вообще ничего не понимаю что тут имелось в виду, кто такой _ordering

Потом говорится о типах, которых вообще в стандарте не существует, какие то strong_equality, дальше упоминается, что их не существует (зачем тогда упоминать?)

Итак, правильный ответ:

если ваш тип просто агрегация других типов:

auto operator<=>(const my_type&) const = default;

компилятор сам разберётся

Если нужно написать своё, то если два "равных" с точки зрения оператора== значения полностью неразличимы для наблюдателя, то strong_ordering.

Если различимы (например какой то из филдов не участвует в сравнении, но логически является частью типа), то weak_ordering

Если иногда у вас вообще не получается как то логично сравнить 2 значения - partial_ordering



Всё верно, этот конкретный фрагмент — перевод, так как я прямо цитировал пропозал Consistent comparison (P0515). Абзацем ранее было написано: «а какой тип, собственно, должен возвращать наш operator<=>, если мы реализуем его своими руками: std::strong_orderingstd::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.

Раздел про слабо упорядоченные типы стал подробнее: появилось детальное объяснение понятия «различимости».

Спасибо @Kelbon и @NeoCodeза ранний фидбек.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории