为什么范围内的v3算法不可管理?

时间:2016-12-29 13:24:02

标签: c++ stl range-v3

似乎范围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);

这是一个设计选择,只有返回新范围/容器的算法/操作才是可管道的吗?

2 个答案:

答案 0 :(得分:3)

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

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

从另一个角度查看情境,在范围-v3视图中进行延迟评估。计算范围中元素的数量不是惰性操作,因为它需要评估整个范围以获得结果。这是一种不同的操作。

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

话虽如此,一些独立的算法也可以作为视图使用,它有意义(如set_intersectionset_differenceset_union算法系列)。

修改:此规则有例外情况。即,函数ranges::to_vectorranges::to_,将管道范围“下沉”到std::vector(或您选择的容器)。

答案 1 :(得分:2)

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

但是你的代码表明你实际上有一个不同的问题。为什么没有允许结束管道链的签名算法?我建议这种算法的命名空间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说,像我们一样,人们会摒弃许多想法,但不会看到深刻的后果。所以也许我们没有看到的想法有些不好。如果他通过你的问题并用评论来启发我们,那就太好了。

当然,他正在使用C ++ 11作为范围-v3而没有针对构造函数的类型化,这个想法更难实现。