What is this version of sort() which takes a container instead of two iterators?
Asked Answered
S

4

5

I was reading Stroustrup's blog on c++ (http://isocpp.org/blog/2014/12/myths-3) when I found an intersting piece of code:

void do_my_sort(vector<double>& v)
{
  sort(v,[](double x, double y) { return x>y; });  // sort v in decreasing order
}

int main()
{
  vector<double> vd;
  // ... fill vd ...
  do_my_sort(v);
  // ...
} 

Notice that the sort does not use the traditional sort(v.begin(), v.end(), ...) which Stroustrup explains:

I used a container version of sort() to avoid being explicit about the iterators.

However, I tried the same code on my C++11 compiler but it fails to compile. I also tried the same on a C++14 compiler using ideone but it too fails to compile, saying that there is no matching call to sort.

Why is this?

Also, Stroustrup next mentions:

I could go further and use a C++14 comparison object:

sort(v,greater<>()); // sort v in decreasing order

I have used comparators like great<>() for sort in C++11 also. Why is he stating that this is a C++14 comparison object?

Seaworthy answered 10/1, 2015 at 21:55 Comment(3)
To use std::sort, you might have to #include <algorithm>Stealth
@Stealth I know that and have already done that. It still says there is no matching call to sort.Seaworthy
There is no container version of sort in the standard, but hopefully soon: ericniebler.github.io/std/wg21/D4128.htmlCordite
B
10

He wrote that himself, it is not standard. Thus you cannot find it in the standard library. You could implement it like this:

template <class Container, class Comp>
void sort (Container& cont, Comp comp) {
    using std::begin;
    using std::end;
    std::sort(begin(cont), end(cont), comp);
}

As Clukester pointed out, there is also boost::sort that offers this functionality.

Bilander answered 10/1, 2015 at 21:59 Comment(4)
Oh ok. I thought it was part of the language standard or was some recently introduced feature. It would be nice if he mentioned that it was a custom built function.Seaworthy
Why not add a default argument to the Comp template? class Comp = less<>?Lariat
@Lariat No reason not to, I just feel that it is not relevant for the question above. I like to keep it as short and simple as possible.Bilander
Totally cheating :) Not nice Stroustrup!Scamp
C
4

I have used comparators like great<>() for sort in C++11 also. Why is he stating that this is a C++14 comparison object?

The C++14 comparison functors have the added ability to take forwarding references for its operator() method and deduced return types. The template argument for the Function Objects collection has been changed to have a default argument of type void and using specialization for that type.

template< class T = void >
struct greater
{
    constexpr bool operator()(const T &lhs, const T &rhs) const;
};

template<>
struct greater<void>
{
    template< class T, class U>
    constexpr auto operator()( T&& lhs, U&& rhs ) const
      -> decltype(std::forward<T>(lhs) > std::forward<U>(rhs));
};
Crossness answered 10/1, 2015 at 22:21 Comment(0)
I
1

Perhaps he is using Boost's sort, not the standard sort as one would expect. So it's boost::sort, not std::sort.

Ignite answered 10/1, 2015 at 22:6 Comment(0)
I
1

Bjarne explains what this sort() is in the blog:

I used a container version of sort() to avoid being explicit about the iterators. That is, to avoid having to write:

std::sort(v.begin(), v.end(), [](double x, double y) { return x > y; });

Nowadays, C++20 has std::ranges::sort to offer, which can do this as well:

std::vector<double> vd{ /* ... */ };

std::ranges::sort(vd);
// equivalent to ...
std::ranges::sort(vd.begin(), vd.end());

Note that this solution works for all ranges, such as std::array, std::span, std::vector, etc.

A way to imitate it in C++14 would be:

// std::less<void> can be implemented in C++11 too
template <class Container, class Comp = std::less<void>>
void sort(Container&& cont, Comp comp = {}) {
    using std::begin;
    using std::end;
    std::sort(begin(cont), end(cont), std::move(comp));
}

Note: this is very similar to @BaummitAugen's solution, however, it takes a forwarding reference to allow sorting containers which are not passed as lvalues.

Note: calling std::sort with cont.begin() and cont.end() would not work if Container is an array.

Ito answered 23/9, 2023 at 7:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.