Почему для концепции Sortable требуется полностью упорядоченный тип значения, а для std::sort требуется только меньше, чем сопоставимый?

В последнем документе о концепциях N3701 , есть следующий пример с алгоритмом sort:

template<typename Cont>
  requires Sortable<Cont>()
void sort(Cont& cont)

где понятие Sortable определяется как

template<typename T>
concept bool Sortable()
{
  return Permutable_container<T>() && Totally_ordered<Value_type<T>>();
}

где Totally_ordered, что неудивительно, определяется как

template<typename T>
constexpr bool Totally_ordered()
{
  return Weakly_ordered<T>() && Equality_comparable<T>();
}

и, в свою очередь, Equality_comparable определяется как

template<typename T>
constexpr bool Equality_comparable()
{
  return requires(T a, T b) {
    {a == b} -> bool;
    {a != b} -> bool;
  };
}

Я не нашел определения Weakly_ordered, но я думаю, что оно должно выглядеть так (я прав?)

template<typename T>
constexpr bool Weakly_ordered()
{
  return requires(T a, T b) {
    {a < b} -> bool;
    {a <= b} -> bool;
    {a > b} -> bool;
    {a >= b} -> bool;
  };
}

Суть в том, что в этом определении, если я хочу отсортировать std::vector<T>, мне нужно, чтобы T предоставил все операторы сравнения <, <=, >, >=, ==, !=. Однако на протяжении всей жизни C++ std::sort требовался только оператор <! Вот что cppreference говорит о std::sort:

Сортирует элементы в диапазоне [первый, последний) в порядке возрастания. Порядок равных элементов не гарантируется. Первая версия использует оператор‹ для сравнения элементов, вторая версия использует данный объект функции сравнения comp.

Так что же, означает ли это, что в будущем C++ с концепциями для v типа std::vector<T>, где T предоставляет только operator<, std::sort(v.begin(), v.end()) будет компилироваться, а std::sort(v) — нет? Это звучит безумно.

Я проверил это в текущей реализации ranges-v3 Эрика Ниблера, и все работает так, как я описал. . Код не компилируется, если не указаны все операторы.

См. также соответствующее обсуждение: https://github.com/ericniebler/range-v3/issues/ 271


person Mikhail    schedule 05.01.2016    source источник


Ответы (1)


Концепции TS не концептуализируют стандартную библиотеку. Это был просто пример; больше ничего.

Версия Ranges TS sort требует Sortable, что по умолчанию использует класс сравнения std::less<>. Однако, казалось бы, std::less<>::operator() накладывает требование TotallyOrdered на типы своих параметров. Так вот откуда это. Об этом есть примечание в P0021R0 (PDF):

[Примечание редактора: удалите таблицу [lessthancomparable] в [utility.arg.requirements]. Замените использование LessThanComparable на TotallyOrdered (признавая, что это критическое изменение, которое ужесточает требования к типу). Замените ссылки на [lessthancomparable] ссылками на [concepts.lib.compare.totallyordered]]

Добавлен акцент. Общие проблемы, связанные с этим по-видимому, отложены, ожидая других языковых функций (таких как неявное создание всех остальных операторов исключительно на основе operator< или чего-то подобного).

Вы можете просто использовать (нормальную) версию функции сравнения. Или вы можете просто использовать версию итератора std::sort, которая не будет использовать никаких понятий.


Следует также отметить, что с введение "оператора космического корабля" в C++20 ( как только мы увидели, что Ranges TS интегрирован в стандарт), вся эта дискуссия фактически становится спорной. Простое объявление auto operator<=>(const MyType &) = default; в классе, и вдруг ваш тип полностью упорядочен.

person Nicol Bolas    schedule 05.01.2016
comment
Я проверил это в текущей реализации range-v3 Эрика Ниблера (github.com/ericniebler/range-v3), и это работает именно так, как я описал. Код не компилируется, если не указаны все операторы. Однако для этой реализации требуется IndirectCallableRelation. - person Mikhail; 05.01.2016
comment
Проверка с 2020 года. Интересно, как мы должны передавать предикат сортировки, определяющий общий порядок. - person sehe; 20.04.2020
comment
@sehe: Это довольно просто: концепция sortable принимает callable, который является предикатом, который должен накладывать значение indirect_strict_weak_order в отношении типов значения/ссылки. В принципе, он работает так же, как и всегда. Это предикат по умолчанию ranges::less, который накладывает общий порядок на заданные T и U. - person Nicol Bolas; 20.04.2020
comment
@NicolBolas, это ничего не говорит мне об интерфейсе. Одного operator() недостаточно для указания сравнения меньшего и равенства. Но я продолжу копать ranges::less - person sehe; 20.04.2020
comment
Ну что ж. ranges::less не является шаблоном. Таким образом, я мертв в воде, даже если я могу использовать преобразование моего типа в некоторый тип T, который имеет определенный общий порядок. Как правило, требуется иметь возможность указывать альтернативные порядки для типа значения без изменения определения этого типа. - person sehe; 20.04.2020
comment
@sehe: Вы можете сделать это. Просто укажите свой собственный предикат. Ваш предикат не обязан устанавливать общий порядок, только строгий-слабый порядок. Если вы не используете ranges::less, вам не нужно иметь дело с его требованиями к порядку. - person Nicol Bolas; 20.04.2020
comment
Ой. Ага. Это... странно. И помогает. Просто начните указывать std::less<>{} везде. Хм. Не самый лучший. Тоже не самое худшее. Спасибо - person sehe; 20.04.2020
comment
@sehe: Считаете ли вы перегрузку operator< типа частью определения типа? Потому что если вы это сделаете, то std::less не поможет вам указать альтернативные порядки для типа значения; это позволит вам использовать только порядок operator< типа. Думаю, я просто не понимаю, что вы пытаетесь сделать, если std::less является решением, особенно в контексте С++ 20, где добиться полного упорядочения довольно просто. - person Nicol Bolas; 20.04.2020
comment
@NicolBolas Нет. Иногда естественный порядок по умолчанию может быть частью интерфейса (отсюда std::less<>), но хороший интерфейс должен иметь возможность принимать другие предикаты порядка. Итак, я немного раздражен, почему передача std::less<> (требующая строгого слабого упорядочения) в порядке, когда range-lib требует полного упорядочения. Бьюсь об заклад, это просто случайный побочный эффект доступных концепций. - person sehe; 20.04.2020
comment
Давайте продолжим обсуждение в чате. - person sehe; 20.04.2020