8

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

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

4

2 回答 2

4

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

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

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

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

话虽这么说,一些独立的算法也可以作为视图使用,这很有意义(如set_intersection,set_differenceset_union系列算法)。

编辑:这条规则有例外。即,函数ranges::to_vectorranges::to_,它将管道范围“下沉”到 a std::vector(或您选择的容器)中。

于 2018-04-24T09:18:38.360 回答
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 说,人们像我们一样,从臀部发出许多想法,但看不到其深远的后果。所以也许我们看不到这个想法有什么不好的地方。如果他通过您的问题并用评论启发我们,那就太好了。

当然,他在 range-v3 中使用了 C++11,并且没有构造函数的类型推导,这个想法更难实现。

于 2018-06-10T02:48:27.327 回答