简体   繁体   中英

Why Sortable concept requires totally ordered value type, while std::sort only requires “less than” comparable?

In the latest paper on concepts N3701 , there is the following example with the sort algorithm:

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

where Sortable concept is defined as

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

where Totally_ordered , not surprisingly, is defined as

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

and in turn Equality_comparable is defined as

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

I didn't find the definition of Weakly_ordered , but I believe it should look like this (am I right?)

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;
  };
}

Bottom line, in this definition, if I want to sort std::vector<T> , I need T to provide all comparison operators < , <= , > , >= , == , != . However, during the whole life of C++, std::sort only required operator < to be provided! Here is what cppreference says about std::sort :

Sorts the elements in the range [first, last) in ascending order. The order of equal elements is not guaranteed to be preserved. The first version uses operator< to compare the elements , the second version uses the given comparison function object comp.

So what, does that mean that in future C++ with concepts, for v of type std::vector<T> where T provides only operator< , std::sort(v.begin(), v.end()) will compile, while std::sort(v) will not? This sounds crazy.

I checked this in the current ranges-v3 implementation by Eric Niebler, and it works just like I described. Code does not compile unless all operators are provided.

See also related discussion: https://github.com/ericniebler/range-v3/issues/271

The Concepts TS does not conceptualize the standard library. It was merely an example; nothing more.

The Ranges TS version of sort requires Sortable , which defaults its comparison class to std::less<> . However, it would seem that std::less<>::operator() imposes the TotallyOrdered requirement on the types of its parameters. So that's where it comes from. There's a note about this in P0021R0 (PDF) :

[Editor's note: Remove table [lessthancomparable] in [utility.arg.requirements]. Replace uses of LessThanComparable with TotallyOrdered ( acknowledging that this is a breaking change that makes type requirements stricter ). Replace references to [lessthancomparable] with references to [concepts.lib.compare.totallyordered]]

Emphasis added. The general issues surrounding this appear to be on-hold , pending other language features (like implicit creation of all other operators based solely on operator< or somesuch).

You could simply use a (sane) version of a comparison function. Or you could just use the std::sort iterator version, which won't use concepts of any kind.


It should also be noted that, with the introduction of the "spaceship operator" in C++20 (the earliest we could see the Ranges TS integrated into the standard), this whole discussion effectively becomes moot. A simple auto operator<=>(const MyType &) = default; declaration in the class, and suddenly your type is totally ordered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM