find_if 算法的定义如下:
template<class InputIterator, class T, class Predicate> inline
InputIterator find_if(
InputIterator First,
InputIterator Last,
Predicate Predicate
)
它和find算法很类似返回的是找到元素的佚代器。它的第三个参数是一个函数
指针(function pointer)或函数对像(object functional)如果是函数对像,它的
定义可以是这样。
template <class T>
class fun
{
public:
bool operator()(const T &a)const
{
if(a > 10)
return true;
}
};
这里实现了一个找出大于30的元素(当然元素不一不是int型的)这里是一个小例子
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include "time.h"
using namespace std;
int _rand()
{
return rand()%100;
}
template <class T>
class fun
{
public:
bool operator()(const T &a)const
{
return a>30;
}
};
int main(int argc, char* argv[])
{
srand(time(NULL));
vector<int> vec(16);
generate(vec.begin(),vec.end(),_rand);
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout << endl;
vector<int>::iterator itr =vec.begin();
while(itr != vec.end())
{
itr = find_if(itr,vec.end(),fun<int>());
if(itr != vec.end())
{
cout <<*itr << " ";
itr++;
}
}
return 0;
}
但是,如果我们要比较的数是一个在运行时改变的数,比如,第一次要找大去30
的,第二次要找大于35的,这如何时实呢?对,binder2nd()!
它是一个模版类定义在<functional>头文件里。
template<class Operation>
class binder2nd : public unary_function <
typename Operation::first_argument_type,
typename Operation::result_type>
{
public:
typedef typename Operation::first_argument_type argument_type;
typedef typename Operation::result_type result_type;
binder2nd(
const Operation& _Func,
const typename Operation::second_argument_type& _Right
);
result_type operator()(
const argument_type& _Left
) const;
result_type operator()(
argument_type& _Left
) const;
protected:
Operation op;
typename Operation::second_argument_type value;
};
怎么样,看晕了吧?简单说下_Func是要绑定的函数对象,_Right是要绑定的二原
函数的第二个参数。那第一个参数呢?是留给find_if用的。这个函数对象从
binary_function派生出来的,我们看看看binary_function的定义:
template<class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
它是一个用模版定义的类,用来对函数对象提供C++标准模版库的支持,
first_argument_type 表示第一个参数类型,second_argument_type 表示第二个
参数类型result_type表示返回值类型。C++库的函数对象都是从这个类派生出来
的。
说了这么多怎么用它呢:我还是给个例子吧!功能和上面的差不多,找出大于30
的数。看好了!
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include "time.h"
using namespace std;
template<class T>
class fun: public binary_function<T, T, bool>
{
public:
result_type operator() ( const first_argument_type a,const
second_argument_type b ) const
{
return a>b;
}
};
int _rand()
{
return rand()%100;
}
int main(int argc, char* argv[])
{
srand(time(NULL));
vector<int> vec(16);
generate(vec.begin(),vec.end(),_rand);
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout << endl;
vector<int>::iterator itr =vec.begin();
while(itr != vec.end())
{
itr = find_if(itr,vec.end(),binder2nd<fun<int> >(fun<int>
(),30));
if(itr != vec.end())
{
cout <<*itr << " ";
itr++;
}
}
return 0;
}
{
public:
my_equal_to()
{
pt = CPoint3D(0, 0, 0);
}
my_equal_to(CPoint3D pt1) {pt = pt1;}
bool operator () (const CPoint3D &point)
{
return point == pt;
}
public:
CPoint3D pt;
};
int main(int argc, char* argv[])
{
vector<CPoint3D> vectPtArray;
vectPtArray.push_back(CPoint3D(1.0, 1.0, 1.0));
vectPtArray.push_back(CPoint3D(1.0, 2.0, 1.0));
vectPtArray.push_back(CPoint3D(1.0, 1.0, 3.0));
vectPtArray.push_back(CPoint3D(1.0, 1.0, 4.0));
vectPtArray.push_back(CPoint3D(1.0, 1.0, 6.0));
CPoint3D pt(1.0, 1.0, 6.0);
vector<CPoint3D>::iterator it = find_if(vectPtArray.begin(), vectPtArray.end(), my_equal_to(pt));
pt = CPoint3D(1.0, 2.0, 1.0);
vector<CPoint3D>::iterator it1 = find(vectPtArray.begin(), vectPtArray.end(), pt);
if (it != vectPtArray.end())
{
cout<<"("<<(*it).x<<","<<(*it).y<<","<<(*it).z<<")\n";
}
if (it1 != vectPtArray.end())
{
cout<<"("<<(*it).x<<","<<(*it).y<<","<<(*it).z<<")\n";
}
return 0;
}
对map使用find_if
map结构定义如下:
map<pair<int, int>, Module *> Mmap;
typedef Mmap:iterator MmapIt;
现在要编写一个查找Mmap结构的函数,如果自己写for循环,是这个样子:
Mmap mmap;
Module *lookup_by_first_1st(int val){
}
不管查找原则是什么,这样写很省事。如果要使用STL的find_if,应该是这个样子:
Module *lookup_by_first_2nd(int val){
}
其中,Access_hit()是个二元谓词函数,它接受的第二个自变量是val, 那么第一个自变量是什么呢?
这个问题的答案对于STL新的使用者来说,其回答也许不是C++STL所规定的那样,是容器的值类型,在这里就是pair<pair<int, int>, Module *>, 而是更自然的MmapIt!当然,可能有些人的自然反应正好相反,和C++的标准一样,而我呢,属于那另外的,直觉总是与正解相反的人群。
也许,真的是直觉有问题:毕竟那个谓词函数所使用的应该是值,基本上没有可能性会使用iterator,所以标准的规定也是自然的。对于for_each用到的函数,传递的参数也是值类型,所以,也就没什么好抱怨的。只是稍稍有点怪异的地方是:map的值类型是个pair,所以,要保持一致的话,Mmap的写法应该是这样:
map<pair<pair<int, int>, Module *>> Mmap;
但是,这么写太怪异了,所以,还是遵从C++的规定,这样同时也就遵循了最简原则,只是要记住的东西多一点而已。不过,东记一点,西记一点,加起来就是可观的记忆负担。这就是C++的特点:虽然优美,但是复杂。要记的东西太多,因为表记上不一致的地方就需要规定来解套,或者在用强类型和祈使句式表达起来困难的场合,就得使用新发明的语法,比如模板。C++的这些困难,在动态函数式语言如Lisp那里,根本就不是问题。
把函数写完整,Access_hit的定义是这样:
struct Access_hit : public std::binary_function<pair<pair<int, int>, Module *>, const int, bool> {
};