Generating functors with iterator behavior

前端 未结 4 1738
温柔的废话
温柔的废话 2021-02-04 13:53

I have a question, which very likely has been asked like this before, because I think what I want is something that a considerable amount of people would want. However I could n

4条回答
  •  面向向阳花
    2021-02-04 14:25

    Sure, we can just write our own iterator:

    template 
    class func_iterator
    : std::iterator<
        std::random_access_iterator_tag,
        typename std::result_of::type,
        Value,
        typename std::result_of::type,
        typename std::result_of::type>
    { .. };
    

    This iterator needs three things: a function (F f), the current value and the step (Value value, step). Dereferencing will calculate the value of the function each time:

    using T = typename std::result_of::type;
    T operator*() { return f(value); }
    

    Selected iterating functions (omitting postfix since they look the same):

    func_iterator& operator++() {
        value += step;
        return *this;
    }
    
    func_iterator& operator--() {
        value -= step;
        return *this;
    }
    
    func_iterator operator+(Value amt) {
        return func_iterator{f, value + amt * step, step};
    }
    

    Difference between iterators (for std::distance) and equality:

    Value operator-(const func_iterator& rhs) {
        assert(step == rhs.step);
        return (value - rhs.value) / step;
    }
    
    bool operator==(const func_iterator& rhs) {
        return value == rhs.value && step == rhs.step;
    }
    

    And finally a function to make an iterator for us:

    template 
    func_iterator make_func_iterator(F f, Value v, Value s = 1) {
        return func_iterator{f, v, s};
    }
    

    Putting that together, I can do something like:

    auto sq_it = make_func_iterator([](int x){return x*x;}, 1);
    std::vector squares{sq_it, sq_it + 10}; // v now holds {1, 4, 9, 16, ..., 100}
    

    Or just:

    // get a bunch of even numbers, complicatedly:
    auto ident = make_func_iterator([](int x){return x;}, 2, 2);
    std::vector evens{ident, ident+200}; // holds {2, 4, ..., 400}
    

提交回复
热议问题