How do I write a range pipeline that uses temporary containers?

前端 未结 6 2434
予麋鹿
予麋鹿 2020-11-30 02:09

I have a third-party function with this signature:

std::vector f(T t);

I also have an existing potentially infinite range (of the

6条回答
  •  忘掉有多难
    2020-11-30 02:43

    Edited

    Apparently, the code below violates the rule that views cannot own data they refer to. (However, I don't know if it's strictly forbidden to write something like this.)

    I use ranges::view_facade to create a custom view. It holds a vector returned by f (one at a time), changing it to a range. This makes it possible to use view::join on a range of such ranges. Certainly, we can't have a random or bidirectional access to elements (but view::join itself degrades a range to an Input range), nor can we assign to them.

    I copied struct MyRange from Eric Niebler's repository modifying it slightly.

    #include 
    #include 
    
    using namespace ranges;
    
    std::vector f(int i) {
        return std::vector(static_cast(i), i);
    }
    
    template
    struct MyRange: ranges::view_facade> {
    private:
        friend struct ranges::range_access;
        std::vector data;
        struct cursor {
        private:
            typename std::vector::const_iterator iter;
        public:
            cursor() = default;
            cursor(typename std::vector::const_iterator it) : iter(it) {}
            T const & get() const { return *iter; }
            bool equal(cursor const &that) const { return iter == that.iter; }
            void next() { ++iter; }
            // Don't need those for an InputRange:
            // void prev() { --iter; }
            // std::ptrdiff_t distance_to(cursor const &that) const { return that.iter - iter; }
            // void advance(std::ptrdiff_t n) { iter += n; }
        };
        cursor begin_cursor() const { return {data.begin()}; }
        cursor   end_cursor() const { return {data.end()}; }
    public:
        MyRange() = default;
        explicit MyRange(const std::vector& v) : data(v) {}
        explicit MyRange(std::vector&& v) noexcept : data (std::move(v)) {}
    };
    
    template 
    MyRange to_MyRange(std::vector && v) {
        return MyRange(std::forward>(v));
    }
    
    
    int main() {
        auto src = view::ints(1);        // infinite list
    
        auto rng = src | view::transform(f) | view::transform(to_MyRange) | view::join;
    
        for_each(rng | view::take(42), [](int i) {
            std::cout << i << ' ';
        });
    }
    
    // Output:
    // 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 9 9 9 9 9 9 
    

    Compiled with gcc 5.3.0.

提交回复
热议问题