std :: for_each在多个迭代器范围内工作

kil*_*gre 11 c++ boost stl c++11

lambda表示法使得stl算法更易于访问.我仍然在学习什么时候它有用以及何时回归到老式的for-loops.通常,有必要迭代两个(或更多)相同大小的容器,使得相应的元素是相关的,但由于某种原因不会被打包到同一个类中.

使用for循环实现的函数如下所示:

template<typename Data, typename Property>
void foo(vector<Data>& data, vector<Property>& prop) {
    auto i_data = begin(data);
    auto i_prop = begin(prop);
    for (; i_data != data.end(); ++i_data, ++i_prop) {
        if (i_prop->SomePropertySatistfied()) {
            i_data->DoSomething();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为了使用for_each,我需要一个处理多个范围的版本; 就像是:

template<typename InputIter1, typename InputIter2, typename Function>
Function for_each_on_two_ranges(InputIter1 first1, InputIter1 last1, InputIter2 first2, Function f) {
    for (; first1 != last1; ++first1, ++first2) {
        f(*first1, *first2);
    }
    return f;
}
Run Code Online (Sandbox Code Playgroud)

使用此版本,上面的代码如下所示:

template<typename Data, typename Property>
void foo_two_ranges(vector<Data>& data, vector<Property>& prop) {
    for_each_on_two_ranges(begin(data), end(data), begin(prop), [](Data& d, Property& p) {
        if (p.SomePropertySatistfied()) {
            d.DoSomething();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

是否有使用stl算法实现相同结果的等效方法?

编辑

我在boost :: range上以boost :: for_each的形式找到了我的问题的确切答案.为了完整起见,我添加了答案,并附带示例代码.

Jon*_*ely 8

1)STL中的算法并不意味着涵盖所有可能的情况,如果您需要for_each_on_two_ranges然后编写它(如您所有)并使用它.STL的美妙之处在于它是如此可扩展,并且你用一个有用的新算法扩展它.

2)如果这不起作用,你不必使用旧的老式for循环,你可以使用花哨的新for循环!

正如另一个答案所说,这boost::zip_iterator是你的朋友,但它不一定难以使用.这是一个使用范围适配器的解决方案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();
}
Run Code Online (Sandbox Code Playgroud)

这个zip函数创建了一个带有begin()end()返回a的成员的适配器boost::zip_iterator,所以循环变量是每个底层容器元素的元组(因为它是一个可变参数模板,你可以为任意数量的容器做这个,所以你不需要写for_each_for_three_rangesfor_each_for_four_ranges等)

你也可以用它 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();
    }
});
Run Code Online (Sandbox Code Playgroud)


kil*_*gre 5

在阅读了一些答案所建议的boost :: zip_iterator和boost :: iterator_range之后,我遇到了boost :: range中扩展算法,并找到了我为两个范围编写的算法的完全并行,但是有了增强范围.

该示例的工作代码将是

#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();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

一些包装器和实用程序功能,与@Jonathan Wakely建议的相似,可以使它更加实用.

  • 请注意,您只需编写`boost :: for_each(data,prop,...)` - 无需调用`make_iterator_range`. (2认同)