std::for_each working on more than one range of iterators

前端 未结 3 399
心在旅途
心在旅途 2020-12-17 18:31

The lambda notation has made stl algorithms more accessible. I am still learning to decide when it\'s useful and when to fall back to good old fashioned for-loops. Often, it

相关标签:
3条回答
  • 2020-12-17 18:35

    After reading up on boost::zip_iterator and boost::iterator_range as suggested by some answers, I came across the extension algorithms in boost::range, and found the exact parallel of the algorithm I wrote for two ranges, but with boost ranges.

    A working code for the example would be

    #include <boost/range/algorithm_ext/for_each.hpp>
    
    template<typename Data, typename Property>
    void foo_two_ranges(vector<Data>& data, vector<Property>& prop) {
        auto rng1 = boost::make_iterator_range(data.begin(), data.end());
        auto rng2 = boost::make_iterator_range(prop.begin(), prop.end());
        boost::for_each(rng1, rng2, [](Data& d, Property& p) {
            if (p.SomePropertySatistfied()) {
                d.DoSomething();
            }
        });
    }
    

    Some wrappers and utility functions, similar in mind to what @Jonathan Wakely suggested, can make this even more usable.

    0 讨论(0)
  • 2020-12-17 18:40

    1) The algorithms in the STL are not meant to cover every possible case, if you need for_each_on_two_ranges then write it (as you have) and use it. The beauty of the STL is it's so extensible, and you've extended it with a useful new algo.

    2) If that doesn't work, you don't have to use good old fashioned for-loops, you can use fancy new for-loops instead!

    As another answer said, boost::zip_iterator is your friend here, but it doesn't have to be hard to use. Here's a solution using a range adaptor that is implemented with zip_iterator

    template<typename Data, typename Property>
    void foo(vector<Data>& data, vector<Property>& prop) {
        for (auto i : redi::zip(data, prop))
            if (i.get<1>().SomePropertySatistfied())
                i.get<0>.DoSomething();
    }
    

    That zip function creates an adaptor with begin() and end() members that return a boost::zip_iterator, so the loop variable is a tuple of the elements of each underlying container (and as it's a variadic template you can do it for any number of containers, so you don't need to write for_each_for_three_ranges and for_each_for_four_ranges etc.)

    You could also use it with for_each

    auto z = redi::zip(data, prop);
    typedef decltype(z)::iterator::reference reference;
    
    for_each(begin(z), end(z), [](reference i) {
        if (i.get<1>().SomePropertySatistfied()) {
            i.get<0>().DoSomething();
        }
    });
    
    0 讨论(0)
  • 2020-12-17 18:57

    std::transform has an overload that operates on two sequences in parallel. You'd need a null output iterator to absorb the results though, if you weren't interested in collecting any.

    0 讨论(0)
提交回复
热议问题