首页 > 解决方案 > 如何在 C++20 范围内将投影与变换结合起来

问题描述

C++20ranges::sort支持投影,这很好,但我想做更复杂的事情,特别是对投影成员上的函数结果进行排序。

对于函数调用,我尝试了转换然后对该视图进行排序,但 C++20 排序似乎不适用于视图,这个答案解释了原因(对于 range-v3)。

换句话说,我可以在不使用 lambda/functor 的情况下编写它吗?

struct S{
    int val;
};

int origin = 47;

// assume we can not change Distance to take S
int Distance(int val){
    return std::abs(val - origin);
}

void my_sort(std::vector<S> ss) {
  std::ranges::sort(ss, std::greater<>{}, [](const S& s){
      return Distance(s.val);
  });
}

标签: c++c++20std-ranges

解决方案


好像你想要函数组合:

void my_sort(std::vector<S>& ss) {
  std::ranges::sort(ss, std::greater<>{}, compose(Distance, &S::val));
}

哪里compose(f, g)(x)f(g(x))。Boost.Hof 有一个compose,在 range-v3 的某个地方也有一个。但是标准库中没有。


对于函数调用,我尝试了转换,然后对该视图进行排序,

sort(r, less(), f)和之间有很大的区别sort(r | transform(f), less()):前者r使用函数f作为排序键进行排序,后者专门对转换后的值进行排序。一个展示差异的具体例子:

struct X {
    int i;
    int j;
};

vector<X> xs = {X{1, 2}, X{2, 1}, X{0, 7}};

// this would give you (0, 7), (1, 2), (2, 1)
// because we're sorting by the i
ranges::sort(xs, less(), &X::i);

// this would have given you (0, 2), (1, 1), (2, 7)
// because we're sorting the i's independently
ranges::sort(xs | views::transform(&X::i), less());

推荐阅读