【问题标题】:Why aren't range v3 algorithms pipeable?为什么范围 v3 算法不能通过管道传输?
【发布时间】:2016-12-29 13:24:02
【问题描述】:

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

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

【问题讨论】:

  • “调整右值非范围是非法的”但我实际上在 n4128 中找不到任何内容来禁止您的代码。也许您的实现不完整(当然不是不可能),或者我浏览论文的速度太快了(技术性很强)。

标签: c++ stl range-v3


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    【解决方案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,并且没有构造函数的类型推断,这个想法更难实现。

    【讨论】:

      猜你喜欢
      • 2022-07-19
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      • 2014-09-21
      • 2013-11-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多