2009-04-17 14 views
24

std :: for_eachアルゴリズムを使用しているときに、特定の条件が満たされたときにどのように中断しますか?std :: for_eachループで中断する

+0

私は個人的にはforループから早く終了したくありません。 IMO、forループは、完全に反復処理が必要な場合にのみ使用する必要があります。その間に入りたい場合は、他のループ構造を考慮してください。 –

+4

試してください:std :: find_if –

答えて

10

find_ifアルゴリズムを使用すると、iterated要素に適用された述語条件がtrueを返すイテレータを停止して返すことができます。ですから、あなたの述語は、継続/中断条件としてブール値を返すように変更する必要があります。

ただし、これはハックなので、アルゴリズムを使用できます。

もう1つの方法はBOOST_FOREACHを使用することです。

+0

はい私はそれを行うことができますが、条件が満たされるまで、ループ内の要素にいくつかの演算を適用したいのですが? – Naveen

+0

Naveen、それは何ですか?要素に対する操作はまったく可能です。いつでもあなたは "壊す"ことができます。ループは終了します。 –

+0

find_ifは入力イテレータを受け付け、イテレータは出力しません。次に、ループを手動で実装するか、BOOST_FOREACHを使用することをお勧めします。 –

2

例外をスローしないかぎり、それを行うことはできませんが、例外を指定してフロー制御を行わないため、これはお勧めできません。

更新:明らかに、Boostにはfor_each_ifがあります。かもしれません。助けてください、しかしあなたはBoostを使用していません。

+0

あなたはfor_each_if()を使用するためにブーストする必要はありません。実装が簡単です。 –

+0

そうですが、問題は「for_each_if()を実装する方法」ではありません。 –

+0

for_each_ifは問題も解決しません。 「ある点の後でコードに要素を何もしないようにするにはどうすればよいのですか」ではなく、「反復を完全に停止するにはどうすればよいか」ではありませんでした。反復が早期に終了する可能性がある場合は、全体の範囲をトラバースするために多少の重大なパフォーマンスコストがかかる可能性があります。だから答えは例外か何もない。 (何も "再設計するので、あなたは壊れないようにするか、for_each for thisを使用しない"という意味です。) – jalf

13

あなたのファンクタから例外をスローすることによってfor_each()から壊れることがあります。しかしこれはしばしば良い考えではなく、選択肢があります。

ファンクタに状態を保持できます。 'break'条件が検出された場合は、単にファンクタにフラグを設定してから、それ以降の繰り返しごとに、ファンクタの処理を行わずに戻ります。明らかに、これは反復を停止しません。大規模なコレクションでは高価になる可能性がありますが、少なくとも作業の実行を停止します。

コレクションがソートされている場合は、中断したい要素を見つけることができます。そして、for_eachをbegin()から返された要素find()に渡します。

最後に、for_each_if()を実装できます。これは繰り返しを止めることはありませんが、述部がfalseと評価された場合は作業を行うファンクタを評価しません。 for_each_xxx()という2つのフレーバーがあります。演算子==()がtrueに評価され、2つのファンクターが必要な場合は値をとり、作業を実行します。比較演算子find_if()を実行するものと、比較演算子が真と評価した場合に作業を実行するものとがあります。

/* --- 

    For each 
    25.1.1 

     template< class InputIterator, class Function, class T> 
      Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f) 

     template< class InputIterator, class Function, class Predicate > 
      Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f) 

    Requires: 

     T is of type EqualityComparable (20.1.1) 

    Effects:  

     Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold: 

      1: *i == value 
      2: pred(*i) != false 

    Returns:  

     f 

    Complexity: 

     At most last - first applications of f 

    --- */ 

    template< class InputIterator, class Function, class Predicate > 
    Function for_each_if(InputIterator first, 
         InputIterator last, 
         Predicate pred, 
         Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(pred(*first)) 
       f(*first); 
     } 
     return f; 
    }; 

    template< class InputIterator, class Function, class T> 
    Function for_each_equal(InputIterator first, 
          InputIterator last, 
          const T& value, 
          Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(*first == value) 
       f(*first); 
     } 
     return f; 
    }; 
+0

例外をスローすることで中断できます。しかし、場合によってはfind()の方が良いでしょう。少なくとも – jalf

+0

Trueです。他の入力を組み込むために編集された応答。 –

+0

私はちょうどコードを読んだ後、この答えをupvoted、しかし、私はあなたが実際に条件が成立しなければスローする必要がない限り、早期にループを壊すために例外をスローすることは決して良い考えではないと言わなければならない。 –

0

例外をスローします。それが良いアイデアなのかどうかは、@Danというスタイルの質問ですが、あなたのデザインにもっと問題があるかもしれません。 for_eachは、あなたの関数がセット全体に均一に適用できることを暗黙的に前提とする、ある種の関数型プログラミングスタイルを意図しています。だから、もしあなたがならばは壊れる必要があり、それは珍しい状態に収まる可能性があり、したがって例外にふさわしい。

もう1つの解決策と、より機能的な解決策は、一部のアプリケーションに影響を与えないように機能を記述し、効果を持たないように書くことです。したがって、たとえば、集計関数を使用している場合は、「壊れた」ケースでは0を加算します。

+3

フロー制御の例外をスローすることはスタイル上の問題ではありません。それは味の問題です。悪い味、つまりです。 –

+1

それは味よりも盲目の熱狂の問題のように聞こえる。他のほとんどのソリューションよりも、よりシンプルでクリーンでエレガントな仕事をします。私はちょっとチャーリーとこれに同意します。あなたがfor_eachから壊す必要がある場合は、1)おそらく基礎となる設計上の問題があり、2)例外を投げるのが最も簡単な解決策です。 例外がきれいに分離できれば(それはtry/catchで囲む必要があるコードの1行です)、フロー制御に使用することは許容されます。 – jalf

+0

これは古い反抗的な熱狂のようなものです。はい、gotosは有害な可能性がありますが、時にはいくつかの言語で利用可能なオプションの中で最も優れています。 –

6

条件が満たされていない状態でいくつかのアクションを実行するには、std::find_ifなどのアルゴリズムを変更する必要がありますか?

+2

これは簡単な方法です。あなたが止めたいときに真に戻ります。 –

4

すでに他の人に示されているように、IMHOがコードを難読化するという回避策でしか達成できません。

私の提案はfor_eachを通常のforループに変更することです。これは、あなたが休憩を使用している(そして、おそらく続行している)他の人に見せやすくします。

20

std :: any_of(またはstd :: all_ofまたはstd :: none_of)を使用できます。このように:

std::vector<int> a; 
// ...  
std::all_of(a.begin(), a.end(), [&](int val) { 
    // return false if you want to break, true otherwise 
    }); 

しかし、これは無駄な溶液(戻り値が本当に何のために使用されていない)であり、あなたはあなた自身のループを書く方がいいでしょう。

+2

本当に助けられた最高の答え – York

+0

すばらしい答え... – Ash

関連する問題