14

我有一个需要操作的元素集合,在集合上调用成员函数:

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

对于不带参数的调用函数,它非常简单:

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

如果我希望调用的函数有一个参数,则可以做类似的事情。

我的问题是,如果满足某些条件,我想在向量中的元素上调用一个函数。 std::find_if返回满足谓词条件的第一个元素的迭代器。

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

我希望找到满足谓词的所有元素并对其进行操作。

我一直在寻找“ find_all”或“ do_if”等价物的 STL 算法,或者我可以用现有的 STL 做到这一点的方法(这样我只需要迭代一次),而不是自己滚动或简单地做一个标准使用 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()。这就是 lambda 真正闪耀的地方。例如,如果 MyPred 的意思是“可被 2 整除”:

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


更新: 使用 C++0x lambda 语法执行此操作也非常好(继续将谓词作为模 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 beta 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()alist是 O(n) 的实现,但我还没有看到任何 STL 实现调用end()avector不是 O(1) —— 主要是因为vectors 保证具有随机-访问迭代器。

即便如此,如果您担心效率低下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被认为是对 boost 的最终补充。实现自己的并不难。

于 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 回答