Я хотел бы повторить следующее с BOOST FOREACH
std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
i1 < v1.end() && i2 < v2.end();
++i1, ++i2 )
{
doSomething( *i1, *i2 );
}
Я хотел бы повторить следующее с BOOST FOREACH
std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
i1 < v1.end() && i2 < v2.end();
++i1, ++i2 )
{
doSomething( *i1, *i2 );
}
Итерация по двум вещам одновременно называется "zip" (от функционального программирования), а Boost имеет zip-итератор:
Ипотека zip обеспечивает возможность параллельного итерации по нескольким контролируемых последовательностей. Создан zip-итератор из кортежа итераторов. Перемещение итератора zip перемещает все итераторы параллельно. Развертывание zip-итератора возвращает кортеж который содержит результаты разыменования отдельных итераторов.
Обратите внимание, что это итератор, а не диапазон, поэтому для использования BOOST_FOREACH
вам придется записать два из них в iterator_range или pair
. Так что это будет некрасиво, но с некоторой осторожностью вы, вероятно, можете придумать простой zip_range
и написать:
BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
Или специальный случай для 2 и используйте std::pair
, а не boost::tuple
.
Я полагаю, что поскольку doSomething
может иметь параметры (int&, int&)
, на самом деле мы хотим a tuple<int&,int&>
. Надеюсь, что это сработает.
Если вы используете boost, я думаю, что он должен быть таким простым, как:
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
std::vector<int> v1;
std::vector<int> v2;
// iterate over values
int i1, i2;
BOOST_FOREACH(boost::tie(i1, i2), boost::combine(v1, v2))
std::cout << i1+i2 << "\n"; // sums two vectors
// iterate over references
typedef boost::tuple<int&, int&> int_ref_tuple;
BOOST_FOREACH(int_ref_tuple tup, boost::combine(v1, v2))
tup.get<0>() = tup.get<1>(); // assigns one vector to another
странная часть заключается в том, что boost:: combination не документируется. Во всяком случае, работает для меня.
Если вы хотите использовать BOOST_FOREACH
для одновременного итерации двух векторов, как это было в вашем примере кода, вы должны инкапсулировать оба вектора в класс-оболочку, который должен выставлять функции begin
и end
, Эти функции возвращают пользовательский итератор, который будет использоваться для итерации по оболочке, которая внутренне будет перебирать эти два вектора. Звучит неплохо, но это то, что вы должны делать.
Это моя первая попытка реализовать эту (минимальную реализацию, чтобы продемонстрировать основную идею):
template<typename T>
struct wrapper
{
struct iterator
{
typedef typename std::vector<T>::iterator It;
It it1, it2;
iterator(It it1, It it2) : it1(it1), it2(it2) {}
iterator & operator++()
{
++it1; ++it2; return *this;
}
iterator & operator *()
{
return *this;
}
bool operator == (const iterator &other)
{
return !(*this != other);
}
bool operator != (const iterator &other)
{
return it1 != other.it1 && it2 != other.it2;
}
};
iterator begin_, end_;
wrapper(std::vector<T> &v1, std::vector<T> &v2)
: begin_(v1.begin(), v2.begin()),end_(v1.end(), v2.end())
{
}
wrapper(const wrapper & other) : begin_(other.begin_), end_(other.end_) {}
iterator begin()
{
return begin_;
}
iterator end()
{
return end_;
}
};
И следующий тестовый код. Поскольку он использует обычный цикл for
, потому что ideone не установлен для boost для С++ 0x, или я делаю что-то неправильно, когда включаю его.
int main() {
std::vector<int> v1 = {1,2,3,4,5,6};
std::vector<int> v2 = {11,12,13,14,15};
wrapper<int> w(v1,v2);
for(wrapper<int>::iterator it = w.begin(); it != w.end(); ++it)
{
std::cout << *it.it1 <<", "<< *it.it2 << std::endl;
}
return 0;
}
Вывод:
1, 11
2, 12
3, 13
4, 14
5, 15
Демо: http://ideone.com/Hf667
Это полезно только для экспериментирования и обучения, так как я не утверждаю, что это идеально. Там может быть много улучшений. И @Steve уже опубликовал решение для повышения производительности.
Благодаря ответу Стива Джессопа и замечательным комментариям, я подошел к следующему решению, поэтому, если вы найдете это хорошо, сначала попробуйте ответить Стив Джессоп.;)
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/iterator_range.hpp>
using namespace boost;
int main(int argc, char **argv) {
std::vector<int> vecFirst = assign::list_of(1)(2)(3)(43)(7)(13);
std::vector<double> vecSecond = assign::list_of(53.45)(-23.545)(0.1574)(1.001)(0.0047)(9.7);
BOOST_AUTO(zipSequence,
make_iterator_range(
make_zip_iterator(make_tuple(vecFirst.begin(), vecSecond.begin())),
make_zip_iterator(make_tuple(vecFirst.end(), vecSecond.end()))
)
);
BOOST_FOREACH( BOOST_TYPEOF(*zipSequence.begin()) each, zipSequence) {
std::cout << "First vector value : " << each.get<0>()
<< " - Second vector value : " << each.get<1>()
<< std::endl;
}
}