Практическое значение сильного порядка и слабого порядка
Я читал немного о последовательном сравнении C++20 (т.е. operator<=>
) но не мог понять, в чем практическая разница между strong_ordering
а также weak_ordering
(то же самое касается _equality
версия для этой манеры).
Кроме того, что он очень наглядно описывает заменяемость типа, действительно ли он влияет на сгенерированный код? Добавляет ли это какие-либо ограничения на то, как можно использовать тип?
Хотелось бы увидеть пример из жизни, который демонстрирует это.
2 ответа
Добавляет ли это какие-либо ограничения на то, как можно использовать тип?
Одним очень существенным ограничением (которое не было задумано в первоначальном документе) было принятие значения strong_ordering
P0732 как индикатор того, что тип класса можно использовать как параметр шаблона нетипичного типа. weak_ordering
недостаточно для этого случая из-за того, как должна работать эквивалентность шаблона.
Как правило, возможно, что некоторые алгоритмы просто требуют weak_ordering
но другие алгоритмы требуют strong_ordering
таким образом, возможность комментировать, что для типа может означать ошибку компиляции (обеспечивается недостаточно строгий порядок) вместо простого несоблюдения требований алгоритма во время выполнения и, следовательно, просто неопределенного поведения. Но все алгоритмы в стандартной библиотеке и диапазонах TS, о которых я знаю, просто требуют weak_ordering
, Я не знаю ни одного, который требует strong_ordering
с верхней части моей головы.
Это на самом деле влияет на сгенерированный код?
За пределами случаев, когда strong_ordering
требуется, или алгоритм явно выбирает другое поведение на основе категории сравнения, нет.
На самом деле нет никаких причин для этого. Верно, что стандарт описывает такие операции, как сортировка, в терминах «строгого» слабого порядка , но существует изоморфизм между строгим слабым порядком и полностью упорядоченным разделением исходного набора на классы эквивалентности несравнимости. Редко можно встретить общий код, который интересуется как структурой порядка (которая рассматривает каждый класс эквивалентности как одно «значение»), так и некоторым, возможно, более тонким понятием эквивалентности : обратите внимание, что когда стандартная библиотека использует
<
(или
<=>
) он не использует (что могло бы быть лучше).
Обычный пример для
std::weak_ordering
является строкой без учета регистра, поскольку, например, печать двух строк, которые отличаются только регистром, безусловно, приводит к разному поведению, несмотря на их эквивалентность (под любым оператором). Однако многие типы могут вести себя по-разному, несмотря на то, что
==
: два
std::vector<int>
объекты, например, могут иметь одинаковое содержимое и разную емкость, поэтому добавление к ним может по-разному аннулировать итераторы.
Простой факт состоит в том, что "равенство", подразумеваемое
std::strong_ordering::equivalent
но не
std::weak_ordering::equivalent
не имеет отношения к самому коду, который получит от него выгоду, потому что общий код не зависит от подразумеваемых поведенческих изменений, а неуниверсальный код не должен различать типы упорядочивания, потому что он знает правила для типа на которым он управляет.
Стандарт пытается придать этому различию значение, говоря о «заменяемости», но это неизбежно повторяется, потому что оно может разумно относиться только к самому состоянию, исследуемому сравнениями. Это обсуждалось до публикации C++20, но (возможно, по очевидным причинам) не так много запланированного дальнейшего обсуждения.