似乎范围 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
不是范围,因此在链中进行该操作是没有意义的。在您能够做到的假设情况下,您将无法将该操作的结果链接到另一个视图。
从另一个角度来看情况,在 range-v3 中,视图被懒惰地评估。计算范围内的元素数量不是惰性操作,因为它需要评估整个范围才能获得结果。这是一种不同的操作。
相同的推理可以应用于其他“独立”算法,如ranges::copy
、ranges::sort
、ranges::min_element
等。这些应该被视为相应std
算法的变体(或改进),但也接受范围作为参数,而不是成对的迭代器.
话虽这么说,一些独立的算法也可以作为视图使用,这很有意义(如set_intersection
,set_difference
和set_union
系列算法)。
编辑:这条规则有例外。即,函数ranges::to_vector
和ranges::to_
,它将管道范围“下沉”到 a 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 说,人们像我们一样,从臀部发出许多想法,但看不到其深远的后果。所以也许我们看不到这个想法有什么不好的地方。如果他通过您的问题并用评论启发我们,那就太好了。
当然,他在 range-v3 中使用了 C++11,并且没有构造函数的类型推导,这个想法更难实现。