2012-04-02 8 views
11

ラムダ表記により、stlアルゴリズムのアクセシビリティが向上しました。私はそれがいつ役に立つのか、良い時代のfor-loopsにいつ陥るのかを決めることを学んでいます。 対応する要素が関連しているが、なんらかの理由で同じクラスにパックされないように、同じサイズの2つ(またはそれ以上)のコンテナを繰り返し処理する必要が生じることがよくあります。std :: for_eachは複数のイテレータの範囲で作業しています

それは次のようになります達成するために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のアルゴリズムを使用して同じ結果を達成するための同等の方法はありますか?

EDITは私が範囲::ブースト上で実行されているブースト:: for_eachの形で私の質問に正確な答えを見つけました。私は完全性のためにサンプルコードを使って答えを加えました。

+1

あなたはすでに書いた 'for_each_two_ranges'を使ってみませんか? – Puppy

+1

それは私にとってとても一般的なもののように見えます。すでに誰かが解決したと思います。 – killogre

+6

Boost.Iteratorから 'zip_iterator'があなたの望むことをすると思います。詳細については、http://www.boost.org/doc/libs/1_49_0/libs/iterator/doc/zip_iterator.htmlを参照してください。 – celtschk

答えて

8

1)STLのアルゴリズムは、for_each_on_two_rangesが必要な場合には、すべての可能なケースをカバーするものではありません。 STLの美しさは拡張性があり、あなたはそれを有用な新しいアルゴで拡張しました。

2)これでうまくいかない場合は、古い旧式のfor-loopsを使用する必要はありません。代わりに新しいfor-loopsを使用することができます。

もう1つの答えとして、boost::zip_iteratorはあなたの友人ですが、使用するのは難しくありません。ここでzip関数はboost::zip_iteratorを返すbegin()end()部材とアダプタを作成すること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(); 
} 

を用いて実施される範囲のアダプタを使用して溶液ですので、ループ変数は、それぞれ下にあるコンテナの要素のタプル(ありますそして、あなたはまた、for_each

でそれを使用することができ

)それはあなたがコンテナの任意の数のためにそれを行うことができ可変長テンプレートですので、あなたは for_each_for_three_rangesfor_each_for_four_rangesなどを記述する必要はありませんように10
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(); 
    } 
}); 
+0

それはとてもいいようです。私はそれが可変であり、コードは比較的コンパクトであることが好きです。私はレンジアダプタについていくつかの宿題をする必要があることを知っています。ありがとう! – killogre

+0

Rediはブーストの名前空間ですか?必要なヘッダは何ですか?タンキー。 –

+0

@ JiveDadson、それは私自身の名前空間ではなく、私は仕事[zip](https://gitorious.org/redistd/redistd/blobs/master/include/redi/zip.h)をソースにリンクしました(そしてもう一度やりました今) –

1

std::transformは、2つのシーケンスを並列に処理する過負荷を持ちます。あなたは何かを収集することに興味がない場合は、結果を吸収するためにnull出力イテレータが必要になります。

+0

for_eachとtransformには異なるセマンティクス[リンク](http://drdobbs.com/cpp/184403769)があります。標準では変形が非突然変異であることが必要ですが、for_eachからはそれを必要としません。とにかく、あなたが言及しているオーバーロードは、同一の順方向イテレータに対してのみ機能します。 – killogre

+0

@Killogre: 'std :: transform'は、出力イテレータを入力イテレータの1つに設定することによって、突然変異を許します。しかし、はい、それは本当にこのような状況のために設計されていません。 –

5

いくつかの回答が示唆するようにboost :: zip_iteratorとboost :: iterator_rangeを読んだところ、私はextension algorithms in boost::rangeを見つけ、2つの範囲に対して書いたアルゴリズムの正確な並列性を確認しました。例えば

作業コードは、@ジョナサンWakelyが提案するものと心の中で類似したいくつかのラッパーとユーティリティ機能は、これをさらに使いやすくすることができます

#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(); 
     } 
    }); 
} 

だろう。

+0

インクルードパスは常にWindozeでも/ not \を使用する必要があります。そうでなければ 'path \ names \ like \ this.hpp 'は改行文字とTAB文字を含みます。これにより、Windozeだけでなくすべてのシステムに移植可能になります。 –

+0

スニペットは、Unixに優しい@JonathanWakely :) – killogre

+2

'boost :: for_each(data、prop、...)'と書くことができます。 'make_iterator_range'を呼び出す必要はありません。 – ecatmur

関連する問題