Using ranges allowed me to reduce boilerplate, so it's great but I could not find a way sort either in ascending order or descending order. The following snippet compiles just fine (g++ 10.2.0) and projection really simplifies the code, no need for a lambda.
struct Player {
double score_;
string name_;
};
vector<Player> players{
{10.0, "Thorin"}, {20.0, "Bombur"}, {15.0, "Bofur"}, {5.0, "Bifur"},
{ 2.0, "Balin"}, {25.0, "Kili" }, {23.0, "Fili"}, {4.0, "Dwalin"}
};
std::ranges::sort(players, std::ranges::less{}, &Player::score_ );
for(auto const &player : players) {
cout << "Name = " << std::left << setw(10) << player.name_
<< " Score = " << player.score_ << endl;
}
Now I need to have a boolean controlling ascending or descending order sort.
I would like to write a simple statement like this one:
std::ranges::sort(players, sort_ascending ? std::ranges::less() : std::ranges::greater() , &Player::score_);
but std::ranges::less
and std::ranges::greater
do not have the same type, so a ternary operator won't work.
error: operands to ‘?:’ have different types ‘std::ranges::less’ and ‘std::ranges::greater’
I could have a lambda with capture has shown below, but that's adding more lines of code. Any simple solution in sight?
auto mycompare = [sort_ascending](
const Player &a,
const Player &b) -> bool {
return sort_ascending ^ (b.score_ < a.score_);
};
std::ranges::sort(players, mycompare);
If sort_ascending
is a run-time boolean value, then I don't think it's possible to choose a different function object inside the call to sort
, since the type of this object must be known at compile time.
One option is to refactor this, with a couple of extra lines:
auto sort_if = [] (bool sort_ascending, auto &range, auto proj)
{
if (sort_ascending)
std::ranges::sort(range, std::ranges::less{}, proj);
else
std::ranges::sort(range, std::ranges::greater{}, proj);
};
and call it like this:
sort_if(sort_ascending, players, &Player::score_);
Also, note that your last snippet is broken if sort_ascending
is false. The predicate would end up being the negation of std::less
, which is std::greater_equal
, not std::greater
. This violates the strict-weak-ordering required by sort
, and you end up with undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With