函数对象存在的意义
假设有一个类型为vector<int>的对象,我们想找出其中第一个大于100的元素对应的迭代器,显然我们可以使用如下方法
find_if(v.begin(), v.end(), greater100);
其中greater100是一个函数指针,这个指针对应的函数定义如下
bool greater100(int n)
{
return n > 1000;
}
上述功能实现非常简单,我们使用函数指针就轻松解决了问题,但如果新的需求来了,比如我们还想找出第一个大于100的元素,那我们必须新定义一个新的函数,在这种情况下,一旦新的需求出现,我们必须新定义一个相似却不相同的函数
这太麻烦了,C++中解决这类问题的办法是使用函数对象,这个解决方法相当优雅高效,代码如下:
find_if(v.begin(), v.end(),bind2nd(greater<int>(), x) //设置好需要的x的值即可
bind1st和bind2nd的概念
bind1st和bind2nd是库类模板,它们有个有趣的特性,能将某个值绑定到一个二元函数对象的一个参数之上,例如
bind1st(f, x)将生成一个与f类型一直的函数对象F,并且F(y)的返回值等于f(x,y)的返回值
bind2nd(f, y)将生成一个与f类型一直的函数对象F,并且F(x)的返回值等于f(x,y)的返回值
先来看看预定义函数符的源码,在头文件functional能找到如下代码(VS):
template<class _Ty>
struct greater
: public binary_function<_Ty, _Ty, bool>
{ // functor for operator>
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator> to operands
return (_Left > _Right);
}
};
//预定义函数符的基类
template<class _Arg1,
class _Arg2,
class _Result>
struct binary_function
{ // base class for binary functions
typedef _Arg1 first_argument_type;
typedef _Arg2 second_argument_type;
typedef _Result result_type;
};
我们自定义的函数对象模板依葫芦画瓢即可,在后面的实例代码中我自定义了一个Plus函数对象模板按照上面这种形式定义的函数对象模板都定义了成员first_argument_type,second_argument_type和result_type,实际中这些成员都是放在一个基类模板binary_function中,它们的作用不不言而喻;这几个成员的定义与函数对象需要与函数对象模板bind1st和bind2nd需要进行配合有关,比如bind1st类模板的大致框架如下:
template<T> //仅为说明原理,具体VS的C++库中的源码与此不同
class bind1st
{
bind1st(const T&, const T::first_argument_type&);
T::result_type operator() (const T::second_argument_type);
//...
}
自定义Plus函数对象模板的完整示例代码如下:
#include <iostream>
//#include <algorithm>
#include <functional>
using namespace std;
template <class T>
class Plus: public binary_function<T,T,T>
{
public:
const T& operator()(const T& n1, const T& n2) const
{ return n1 + n2; }
};
void main()
{
Plus<int> a;
cout << a(1,2) << endl;
binder1st<Plus<int> > c = bind1st(a,2); //验证与bind1st结合有效性
cout << c(2) << endl;
Plus<int>::result_type i = 5; //验证是否result_type等的存在
cout << i << endl;
}
运行结果如下:3
4
5