为什么范围 v3 算法不可管道化?

Why aren't range v3 algorithms pipeable?

本文关键字:管道 范围 v3 算法 为什么      更新时间:2023-10-16

看来,范围V3中的算法是不可链的,即:

const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
const auto num_ones = ints | ranges::count(1);

...必须写入功能风格:

const auto num_ones = ranges::count(ints, 1);

这是只有返回新范围/容器的算法/操作的设计选择?

链式视图的输出必须是另一种视图(即范围)。这样,您可以使用更多视图来继续链接结果。

count的结果不是一个范围,因此在链中进行操作是没有意义的。在您能够的假设情况下,您将无法将该操作的结果链接到另一种视图。

从另一个角度查看情况,在范围V3视图中懒散地评估了情况。计算范围内的元素数量不是一个懒惰的操作,因为它需要评估整个范围才能获得结果。这是另一种操作。

相同的推理可以应用于其他"独立"算法,例如ranges::copyranges::sortranges::min_element等。这些算法应将其视为相应std算法的变体(或改进),但也接受范围是参数,而不是成对的迭代器。

话虽如此,某些独立算法也可以作为视图可用,这是有道理的(例如set_intersectionset_differenceset_union算法家族)。

编辑:此规则有例外。也就是说,函数ranges::to_vectorranges::to_,将管道范围"下沉"到std::vector(或您选择的容器)。

某些算法实际上是可链的,您可以在视图和/或操作名称空间中找到它们。

但是您的代码表明您实际上有一个不同的问题。为什么没有具有签名的算法可以结束管道?我建议使用此类算法的名称空间reducer。这是一个工作代码示例:

#include <iostream>
#include <string>
#include <vector>
#include <range/v3/all.hpp>
using namespace std;
namespace view = ranges::view;
namespace action = ranges::action;
namespace reducer {
    template <typename T>
    class count {
        T t;
        public:
        count(T t) : t(t) {}
        template <typename Left>
        T operator()(Left left) {
            return ranges::count(left, t);
        }
    };
    template <typename Left, typename T>
    int operator|(Left left, count<T> right) {
        return right(left);
    }
}
int main (int argc, char * argv[])
{
    const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
    const auto num_ones = ints | reducer::count(1);
    cout << num_ones << endl;
    return 0;
}

埃里克·尼伯勒(Eric Niebler)说,人们像我们一样从臀部中射出了许多想法,但没有看到深远的后果。因此,也许我们看不到的想法有些不好。如果他通过您的问题并通过评论来启发我们会很棒。

当然,他正在为范围V3使用C 11,而没有打字的构造函数这个想法更难实现。