我有一组需要操作的元素,在集合上调用成员函数:
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());
我希望找到符合谓词的所有元素并对其进行操作。
我一直在研究STL算法的“find_all
”或“do_if
”等价物,或者我可以用现有的STL做到这一点(这样我只需要迭代曾经),而不是自己滚动或只是使用for循环和比较进行标准迭代。
答案 0 :(得分: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目前实现此功能。
答案 1 :(得分:12)
我写了一个for_each_if()
和一个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;
};
答案 2 :(得分:6)
可以更改矢量吗?您可能想要查看分区算法。
Partition algorithm
另一种选择是将MyType::myfunc
更改为检查元素,或者将谓词作为参数并使用它来测试它正在运行的元素。
答案 3 :(得分: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()
上调用list
的实现是O(n)的实现,但我还没有看到任何调用end()
的STL实现vector
不是O(1) - 主要是因为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);
}
答案 4 :(得分:0)
它的价值for_each_if被认为是最终的助推器。实现自己并不难。
答案 5 :(得分:0)
答案 6 :(得分:0)
您可以使用Boost.Foreach:
BOOST_FOREACH (vector<...>& x, v)
{
if (Check(x)
DoStuff(x);
}