2

C++20 范围算法支持投影,显然与 STL 算法一样,它们支持自定义比较器。

但我发现令人费解的是投影和比较器的顺序。

我的“问题”(更烦人,我将很快学会使用这种参数顺序)是它破坏了从左到右的代码流。

考虑下面的代码(很抱歉它不短,但这就是重点,以表明在实际代码中,当变量名称不是 2 个字母长时,参数的顺序会使代码更难阅读):

struct PointyPoint {
  int x;
  int y;
};

struct Item {
  std::string name;
  PointyPoint location;
};

//...

  std::ranges::sort(
      items,
      [](const PointyPoint &a, const PointyPoint &b) {
        return std::tie(a.x, a.y) < std::tie(b.x, b.y);
      },
      &Item::location);

我对这段代码的问题是,如果投影在 lambda(比较器)之前,我认为它看起来会更好。

完整的代码神螺栓

我认为这个订单被选中的原因:

  • STL 算法通常将比较器作为第三个参数(迭代器之后的第一个参数),因此它是匹配的
  • 也许自定义比较器比投影更常见,因此避免需要提供该参数
4

1 回答 1

3

我相信您已经提到了自己的推理,但让我加强您的观点:

  • 将 pre-ranges 代码移植到<ranges>应该很简单。想象一下你有一个现有的

    std::sort(data.begin(), data.end(), std::greater<>{});
    

    并想把它变成一个<ranges>算法调用。想象一下你必须和

    std::ranges::sort(data, std::identity{}, std::greater<>{});
    

    这确实构成了阻碍轻松迁移的负担。通过实际订购,您只需将第一个版本更改为

    std::ranges::sort(data, std::greater<>{});
    
  • 使用标准比较是非常低的摩擦,所以如果你需要一个投影,很容易在前面加上一个std::less<>{}. 诚然,您可以对 说同样的话std::identity{},但这并不排除第一点。

最后,本文档中的理性也可能对该主题有所帮助:

对于可选择接受函数/谓词(例如变换、排序)的算法,投影参数遵循函数/谓词。没有允许用户在不指定谓词的情况下指定投影的算法重载,即使默认值就足够了。这是为了减少重载的数量,同时也避免任何可能的歧义。

于 2021-05-28T10:19:06.583 回答