#c #sorting #c 17 #range-v3
Вопрос:
На cppreference вкл std::ranges::less
. в примечаниях мы видим , что:
В отличие
std::less
от ,std::ranges::less
требуется, чтобы все шесть операторов сравнения<
,<=
,>
,>=
,==
и!=
были действительными (черезtotally_ordered_with
ограничение).
Но… почему? Почему бы нам использовать std::ranges::less{}
вместо std::less{}
этого ? Какова практическая ситуация, в которой мы хотим less{}
, только если определены другие операторы сравнения, а не только <
один?
Комментарии:
1. Я не уверен, в чем заключаются все эти небольшие различия, но, по крайней мере, они должным образом ограничены.
2. @крис, но простое ограничение шаблона не может быть единственной причиной для дублирования каждого из них, не так ли? Кроме того, какова цель этих дополнительных ограничений?
3. В частности, по поводу
<
«против всего», я, кажется, припоминаю некоторый консенсус, что для типов довольно глупо иметь<
других, не имея других. Всегда существовали варианты использования аргументов компаратора вместо перегрузки одного типа и отсутствия должной осмотрительности для перегрузки других. Тип также может с таким же успехом предоставлять правильно названный компаратор рядом с классом (например, классStudent
с вложеннойNameComparator
структурой). Тем не менее, это рассуждение о «распространении плохих типов» с таким же успехом может быть 100% — ным предположением, потому что смутная память-ужасный источник.4. (И, конечно, ни один код не нарушен, потому что все они предлагаются в дополнение к старым API, так что это было идеальное время для внесения любых изменений, которые «должны были» быть там все это время.)
Ответ №1:
Какова практическая ситуация, в которой мы хотим использовать{} только в том случае, если определены другие операторы сравнения, а не только
Не все в библиотеке диапазонов основано исключительно на том, что является «практическим». Многое из этого связано с тем, чтобы придать языку и библиотеке логический смысл.
Понятия как языковая функция предоставляет стандартной библиотеке возможность определять значимые комбинации объектов. Сказать, что тип имеет operator<
значение, полезно с чисто практической точки зрения, чтобы сообщить вам, какие операции ему доступны. Но на самом деле это не говорит ничего существенного об этом типе.
Если тип полностью упорядочен, то это логически означает, что вы можете использовать любой из операторов сравнения для сравнения двух объектов этого типа. По идее общего порядка, a < b
и b > a
являются эквивалентными утверждениями. Поэтому имеет смысл, что если код ограничен типами, которые обеспечивают общий порядок, этому коду должно быть разрешено использовать любой оператор.
ranges::less::operator()
не использует никаких других операторов, кроме <
. Но эта функция ограничена типами, моделирующими totally_ordered
концепцию. Это ограничение существует, потому что ranges::less
для этого и предназначено: сравнение типов, которые полностью упорядочены. Это могло бы иметь более узкое ограничение, но это означало бы отбрасывание любого смысла, обеспечиваемого полным упорядочением.
Это также предотвращает предоставление пользователям произвольных сведений о реализации. Например, предположим, что у вас есть шаблон, который принимает некоторый тип T
, и вы хотите использовать T
его в ranges::less
операции на основе. Если вы ограничиваете этот шаблон только наличием operator<
, то вы эффективно поместили свою реализацию в ограничение. У вас больше нет свободы для перехода на ranges::greater
внутреннюю реализацию. В то время как если бы вы ввели std::totally_ordered
свое ограничение, вы бы дали понять пользователю, что ему нужно делать, предоставив себе свободу использовать любые необходимые вам функторы.
А поскольку operator<=>
существует и упрощает реализацию операторов упорядочения в одной функции, практического недостатка нет. Ну, за исключением кода, который должен компилироваться как на C 17, так и на C 20.
По сути, вы не должны писать типы, которые «упорядочены», просто написав operator<
для начала.
Ответ №2:
Насколько я могу судить, основываясь на предложении, идея состоит в том, чтобы просто упростить дизайн функциональных объектов. std::less
является классом шаблона, который требует параметра шаблона и представляет собой однородное сравнение. Этот параметр шаблона можно опустить по умолчанию std::less<void>
, что позволяет проводить разнородные сравнения. Аргумент, по-видимому, заключается в том, что однородный случай не нужен, поскольку он прекрасно обрабатывается гетерогенным подходом, поэтому дизайн может быть значительно упрощен, и шаблон класса вообще не нужен.
Что касается того, почему требуются другие операторы, кроме operator<
того, я не совсем уверен. Мое лучшее предположение состоит в том, что это лишь часть того, что значит иметь общий порядок, определенный в C между двумя, возможно, разными типами.