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();
}
}
}
为了使用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;
}
使用此版本,上面的代码如下所示:
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();
}
});
}
是否有使用stl算法实现相同结果的等效方法?
修改
我在boost :: range上以boost :: for_each的形式找到了我的问题的确切答案。为了完整起见,我添加了答案,并附带示例代码。
答案 0 :(得分: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();
}
zip函数创建了一个带有begin()
和end()
成员的适配器,返回boost::zip_iterator
,因此循环变量是每个底层容器元素的元组(并且因为它是一个可变参数模板,您可以为任意数量的容器执行此操作,因此您无需编写for_each_for_three_ranges
和for_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();
}
});
答案 1 :(得分:5)
按照一些答案的建议阅读了boost :: zip_iterator和boost :: iterator_range之后,我遇到了extension algorithms in 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();
}
});
}
一些包装和实用函数,与@Jonathan Wakely建议的类似,可以使它更加可用。
答案 2 :(得分:1)
std::transform
具有并行操作两个序列的重载。如果你不想收集任何结果,你需要一个空的输出迭代器来吸收结果。