以下を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 );
}
2つのものを同時に反復することは(関数プログラミングから)「Zip」と呼ばれ、 BoostにはZipイテレータがあります :
Zipイテレーターは、複数の制御シーケンスを同時に並列反復する機能を提供します。 Zipイテレータは、イテレータのタプルから構築されます。 Zipイテレーターを移動すると、すべてのイテレーターが並行して移動します。 Zipイテレーターを逆参照すると、個々のイテレーターを逆参照した結果を含むタプルが返されます。
これは範囲ではなくイテレータなので、BOOST_FOREACH
を使用するには、2つを 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&)
があるかもしれないので、実際にはTuple<int&,int&>
が必要だと思います。それがうまくいくことを願っています。
あなたがブーストを使うなら、私はそれが次のように単純であるべきだと思います:
#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 :: combineが文書化されていないことです。とにかく私のために働く。
サンプルコードで行ったように、BOOST_FOREACH
を使用して2つのベクトルを同時に反復処理する場合は、begin
関数とend
関数を公開するラッパークラスに両方のベクトルをカプセル化する必要があります。これらの関数は、内部で2つのベクトルを反復するラッパーを反復するために使用されるカスタムイテレータを返します。よく聞こえませんが、それはあなたがしなければならないことです。
これはこれを実装する私の最初の試みです(基本的なアイデアを示すためだけの最小限の実装):
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はC++ 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
これは完璧だとは主張していないので、実験や学習の目的にのみ適しています。多くの改善があり得ます。そして、@ Steveはすでにboostのソリューションを投稿しています。
スティーブジェソップの回答と素晴らしいコメントのおかげで、私は次の解決策を思いついたので、ニースを見つけたら、スティーブジェソップの回答を最初に投票してください。 ;)
#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;
}
}