14

コレクションのメンバー関数を呼び出して、操作する必要のある要素のコレクションがあります。

std::vector<MyType> v;
... // vector is populated

引数なしで関数を呼び出す場合、それは非常に簡単です。

std::for_each(v.begin(), v.end(), std::mem_fun(&MyType::myfunc));

呼び出したい関数に引数が1つあれば、同様のことができます。

私の問題は、ある条件を満たす場合に、ベクトル内の要素に対して関数を呼び出したいということです。 std::find_if述語の条件を満たす最初の要素にイテレータを返します。

std::vector<MyType>::iterator it  = 
      std::find_if(v.begin(), v.end(), MyPred());

述語を満たすすべての要素を見つけて、それらを操作したいと思います。

私は、「find_all」または「do_if」に相当するSTLアルゴリズム、または既存のSTLでこれを実行できる方法(1回だけ反復する必要があるなど)を検討してきました。 forループと比較を使用した反復。

4

7 に答える 7

20

Boost Lambda はこれを簡単にします。

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>

std::for_each( v.begin(), v.end(), 
               if_( MyPred() )[ std::mem_fun(&MyType::myfunc) ] 
             );

単純な場合は、MyPred() の定義をなくすこともできます。これが、ラムダが真価を発揮するところです。たとえば、MyPred が「2 で割り切れる」という意味の場合:

std::for_each( v.begin(), v.end(), 
               if_( _1 % 2 == 0 )[ std::mem_fun( &MyType::myfunc ) ]
             );


更新: C++0x ラムダ構文でこれを行うことも非常に優れています (モジュロ 2 として述語を続けます)。

std::for_each( v.begin(), v.end(),
               [](MyType& mt ) mutable
               {
                 if( mt % 2 == 0)
                 { 
                   mt.myfunc(); 
                 }
               } );

一見、これは boost::lambda 構文から後退しているように見えますが、より複雑なファンクター ロジックは c++0x 構文で実装するのは簡単なので、より優れています... boost::lambda で非常に複雑なものはすべてトリッキーになります早く。Microsoft Visual Studio 2010 ベータ 2 は現在、この機能を実装しています。

于 2008-10-24T17:47:54.893 に答える
12

私はあなたが探していると思うことをするafor_each_if()とaを書きました。for_each_equal()

for_each_if()述語ファンクターを使用して同等性を評価しfor_each_equal()、任意のタイプの値を取得して、を使用して直接比較しoperator ==ます。どちらの場合も、渡した関数は、同等性テストに合格した各要素で呼び出されます。

/* ---

    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;
    };
于 2008-10-24T17:40:39.197 に答える
6

ベクトルを変更しても大丈夫ですか?パーティションアルゴリズムを確認することをお勧めします。
パーティションアルゴリズム

別のオプションはMyType::myfunc、要素をチェックするか、述語をパラメーターとして取り、それを使用して操作している要素をテストするように変更することです。

于 2008-10-24T17:35:54.527 に答える
1
std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin();
MyPred my_pred;
while(true) {
    i = std::find_if(i, v.end(), my_pred);
    if (i == v.end())
        break;
    matches.push_back(*i);
}

記録として、end()a の呼び出しlistが O(n) である実装を見たことがありますがend()、a の呼び出しvectorが O(1) 以外である STL 実装は見たことがありませvectorん。 -イテレータにアクセスします。

それでも、非効率的な が心配な場合は、次のend()コードを使用できます。

std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin(), end = v.end();
MyPred my_pred;
while(true) {
    i = std::find_if(i, v.end(), my_pred);
    if (i == end)
        break;
    matches.push_back(*i);
}
于 2008-10-24T22:36:54.810 に答える
0

for_each_ifの価値は、ブーストへの最終的な追加と見なされています。独自に実装するのは難しくありません。

于 2008-10-24T17:42:32.033 に答える
0

ラムダ関数 - アイデアは、このようなことをすることです

for_each(v.begin(), v.end(), [](MyType& x){ if (Check(x) DoSuff(x); })  

元の投稿はこちら.

于 2008-10-24T17:52:43.447 に答える
0

Boost.Foreachを使用できます:

BOOST_FOREACH (vector<...>& x, v)
{
    if (Check(x)
        DoStuff(x);
}
于 2008-10-24T19:50:48.060 に答える