BOOSTFOREACHで以下を複製したい
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 );
}
BOOSTFOREACHで以下を複製したい
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イテレータを逆参照すると、個々のイテレータを逆参照した結果を含むタプルが返されます。
これは範囲ではなくイテレータであることに注意してください。使用するには、そのうちの2つをiterator_rangeまたはBOOST_FOREACH
に詰め込む必要があります。ですから、きれいではありませんが、少し注意を払えば、おそらく簡単なものを思い付くことができます。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
デモ: http: //ideone.com/Hf667
私はそれが完璧であるとは主張していないので、これは実験と学習の目的にのみ適しています。多くの改善があります。そして、@Steveはすでにboostのソリューションを投稿しています。
Thanks to the answer of Steve Jessop and the great comments, I came up to the following solution, so if you find that nice, vote up Steve Jessop answer first. ;)
#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;
}
}