1110101001
1110101001

Reputation: 5097

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

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?

Upvotes: 5

Views: 398

Answers (4)

Jan Schultke
Jan Schultke

Reputation: 39633

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.

Upvotes: 1

David G
David G

Reputation: 96810

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

Upvotes: 4

Baum mit Augen
Baum mit Augen

Reputation: 50053

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.

Upvotes: 10

Clukester
Clukester

Reputation: 132

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

Upvotes: 1

Related Questions