6

使用范围可以让我减少样板文件,所以这很好,但我找不到按升序或降序排序的方法。以下代码段编译得很好(g++ 10.2.0),投影确实简化了代码,不需要 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;
  }

现在我需要一个布尔控制升序或降序排序。

我想写一个像这样的简单语句:

 std::ranges::sort(players, sort_ascending ? std::ranges::less() : std::ranges::greater() , &Player::score_);

但是std::ranges::lessstd::ranges::greater没有相同的类型,所以三元运算符不起作用。

error: operands to ‘?:’ have different types ‘std::ranges::less’ and ‘std::ranges::greater’

我可以有一个带有捕获的 lambda,如下所示,但这会添加更多代码行。有什么简单的解决方案吗?

  auto mycompare = [sort_ascending](
                       const Player &a, 
                       const Player &b) -> bool  {
      return sort_ascending ^ (b.score_ < a.score_);

    };
  std::ranges::sort(players, mycompare);
4

1 回答 1

4

如果sort_ascending是运行时布尔值,那么我认为不可能对 的调用中选择不同的函数对象sort,因为在编译时必须知道该对象的类型。

一种选择是重构它,增加几行:

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

并这样称呼它:

sort_if(sort_ascending, players, &Player::score_);

另外,请注意,如果sort_ascending为假,您的最后一个片段将被破坏。谓词最终会成为 的否定std::less,即std::greater_equalnot std::greater。这违反了 所要求的严格-弱排序sort,并且您最终会出现未定义的行为。

于 2020-10-12T14:33:03.693 回答