似乎范围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);
这是一个设计选择,只有返回新范围/容器的算法/操作才是可管道的吗?
答案 0 :(得分:3)
链式视图的输出必须是另一个视图(即范围)。这样,您可以使用更多视图继续链接结果。
count
的结果不是范围,因此在链中进行该操作没有意义。在您能够做到的假设情况下,您将无法将该操作的结果链接到另一个视图。
从另一个角度查看情境,在范围-v3视图中进行延迟评估。计算范围中元素的数量不是惰性操作,因为它需要评估整个范围以获得结果。这是一种不同的操作。
同样的推理可以应用于其他“独立”算法,例如ranges::copy
,ranges::sort
,ranges::min_element
等。这些算法应被视为变体(或改进)相应的std
算法,但也接受范围作为参数,而不是迭代器对。
话虽如此,一些独立的算法也可以作为视图使用,它有意义(如set_intersection
,set_difference
和set_union
算法系列)。
修改:此规则有例外情况。即,函数ranges::to_vector
和ranges::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而没有针对构造函数的类型化,这个想法更难实现。