为什么要写函数对象这篇博客呢?主要原因就是函数对象在STL中用得出神入化,给人一种神来之笔的感觉。不知道你是不是也有同感呢?
学习某个新东西,肯定是这个东西有用,我们有需求。所以在学习的时候,我喜欢把一个东西的来龙去脉全搞清楚。知其然,也要知其所以然。
废话不说,切入正题。
许多算法只使用一些迭代器和一些值在序列上的操作。我们来看下面的代码:在序列中找到第一个值为7的元素
void f(list<int> s){
list<int>::iterator p = find(s.begin(),s.end(),7);
//..........
}
bool less_than_7(int v){
return v<7;
}
void f(list<int> &c){
list<int>::iterator p = find_if(c.begin(),c.end(),less_than_7);
}
存在许多需要函数作为参数传递的使用方法,如:逻辑谓词,算术运算等等。为这类使用中的每一种写一个独立的函数,既不方便,也不是很有效。在很多情况下,对每个元素作用的函数还需要再调用之间保存一些数据,并将其作为许多这类应用的最后结果。与独立函数相比,类成员函数能更好地服务于这种需要。
下面一个拟函数的类,去完成一些求和工作:
template<class T>class Sum{
T res;
public:
Sum(T i=0):res(i){}
void operator()(T x){res = x;}
T result()const{return res;}
};
显然,Sum是为了那些用0初始化,并定义有+=的算法类型设计的。
void f(list<double> &ld){
Sum<double> s;
s = for_each(ld.begin(),ld.end(),s);
cout<<"the Sum is "<<s.result()<<'\n';
}
//我们可以猜测下,for_each()中大概是这样子运行
for_each(.....){
while(ld.begin()!=ld.end()){
s(*ld.begin());
++ld.begin();
}
//..........
}
具有适当定义的对象也能很多的(通常是更好地)作为一个函数使用。例如,将一个类的应用运算符在
线化,比将一个指针传递的函数在线化容易的多。因此函数对象比常规函数执行速度更快。
标准库中提供了许多很有用的函数对象的基类:
template<class Arg,class Res>struct unary_function{
typedef Arg argument_type;
typedef Res result_type;
};
template<class Arg,class Arg2,class Res>struct binary_function{
typedef Arg first_argument_type;
typedef Arg2 second_argument_type;
typedef Res result_type;
};
我们可以利用这些基类派生出自己的类。例如:
template<class T>struct logical_not:public unary_function<T,bool>{
bool operator()(const T&x)const{return !x;}
};
template<class T>struct less:public binary_function<T,T,bool>{
bool operator()(const T&x,const T&y)const{return x<y;}
};
所谓谓词就是想上面这种返回类型为bool的函数对象。具体用法如下:
void f(vector<int>&vi,list<int>&li){
typedef list<int>::iterator LI;
typedef vector<int>::iterator VI;
pair<VI,LI> p1 = mismatch(vi.begin(),vi.end(),li.begin(),less<int>());
//..........
}
在函数mismatch中,less就可以像普通带两个参数的函数一样使用。
接下来,讨论下如何定义自己的能接受函数对象的函数:
在开始之前,我们先来看看STL中for_earch()与find_if()的定义:
template<class _InIt,
class _Fn1> inline
_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{ // perform function for each element
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Func);
_CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));
_CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));
for (; _ChkFirst != _ChkLast; ++_ChkFirst)
_Func(*_ChkFirst);
return (_Func);
}
貌似我们关注的重点在红色部分(额....不给显示红色,应该能看出来我说的红色部分在哪),其他部分是
些安全检查之类操作。
我们再来看看find_if()的源码:
template<typename _InputIterator, typename _Predicate>
inline _InputIterator
find_if(_InputIterator __first, _InputIterator __last,
_Predicate __pred)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
typename iterator_traits<_InputIterator>::value_type>)
__glibcxx_requires_valid_range(__first, __last);
return std::__find_if(__first, __last, __pred,
std::__iterator_category(__first));
}
/// This is an overload used by find_if() for the Input Iterator case.
template<typename _InputIterator, typename _Predicate>
inline _InputIterator
__find_if(_InputIterator __first, _InputIterator __last,
_Predicate __pred, input_iterator_tag)
{
while (__first != __last && !bool(__pred(*__first)))
++__first;
return __first;
}
那么我们先来定义自己的函数。
template<class _Iter1,class _Iter2,class _Fcn>inline
_Iter1 get_first_less(_Iter1 first,_Iter1 last,_Iter2 first2,_Fcn f){
while(first!=last){
if(f(*first,*first2))return first;
}
return last;
}
在使用的时候,这样:
vector<int>::iterator p1 = get_first_less(vin1.begin(),vin1.end(),vin2.begin(),less_than<int>);
下面我们来看看成员函数适配器
当我们写的函数模板的参数为成员函数的时候,我们该怎么办呢?例如:
void draw_all(list<Shap *>&c){
for_each(c.begin(),c.end(),&shap::draw); // 肯定出错
}
成员函数总是需要一个对象去调用它:p->draw(),静态成员函数除外。这个时候我们总需要有一种方便而有效的方式
去建立某种东西,使一个算法能够调用成员函数。
我们先来定义个自己的函数对象。
template<class R,class T>class Mem_fun_t:public unary_function<T*,R>{
R(T::*pmf)();
public:
explicit Mem_fun_t(R(T::*p)()):pmf(p){}
R operator()(T *p)const{
return (p->*pmf)();
}
}
template<class R,class T>Mem_fun_t<R,T>Mem_fun(R(T::*f)()){
return Mem_fun_t<R,T>(f);
}
这样我们就可以处理Shape::draw()了。
void draw_all(list<Shape*>&lsp){ for_each(lsp.begin(),lsp.end(),Mem_fun(&Shape::draw));}
//为了大家的阅读方便,我将测试部分与函数实现部分写在一块儿
#include<iostream>
#include<vector>
#include<algorithm>
using std::for_each;
using std::vector;
using std::cout;
using std::endl;
using std::unary_function;
using std::mem_fun;
template<class T,class R>
class mem_fun_t:public unary_function<T*,R>{
R(T::*pmf)();
public:
explicit mem_fun_t(R(T::*p)()):pmf(p){}
R operator()(T *p){return (p->*pmf)();}
};
template<class T,class R>
mem_fun_t<T,R> mem_fun_my(R(T::*p)()){
return mem_fun_t<T,R>(p);
}
template<class T>
class Check{
T num;
public:
Check(T tmp):num(tmp){}
bool is_positive(){
return num? 1:0;
}
};
template<class _Iter,class _fun>
_Iter check_each(_Iter first,_Iter last,_fun f){
while(first != last)
{
if(!f(*first))
{
cout<<"find ...."<<endl;
return first;
}
++first;
}
return last;
}
void test1(){ //类的成员函数做参数
vector<Check<int>*> vecI;
vecI.push_back(new Check<int>(1));
vecI.push_back(new Check<int>(2));
vecI.push_back(new Check<int>(3));
vecI.push_back(new Check<int>(0));
vector<Check<int>*>::iterator p1 =
check_each(vecI.begin(),vecI.end(),mem_fun_my(&Check<int>::is_positive));
}
template<class T>
class D{
T value;
public:
D(T a=0):value(a){}
T get_value(){
return value;
}
T operator *(){
return value;
}
};
template<class T>
class D_fun{
public:
bool operator()(T *a){
if(**a)return 1;
return 0;
}
bool is_positive(T *a){
if(**a)return 1;
return 0;
}
};
void test2(){ //仿函数做参数
vector<D<int> *> vecD;
vecD.push_back(new D<int>(1));
vecD.push_back(new D<int>(2));
vecD.push_back(new D<int>(3));
vecD.push_back(new D<int>());
vector<D<int> *>::iterator p1 = check_each(vecD.begin(),vecD.end(),D_fun<D<int>>());
//vector<D<int> *>::iterator p1 =
// check_erach(vecD.begin(),vecD.end(),mem_fun_my(&D_fun<D<int>>::is_positive));//错误,必须有对象,才能调用成员函数
}
//template<class T>
typedef bool (*fun_ptr)(D<int> *);//这里不能用指向模板函数的模板指针,因为这样做指针的类型不能确定 故编译时候会出错
//上述想法行不通,下面是改进方案。如果实在想做一个函数指针模板,我们可以这样...
template<class T>
struct Fun_ptr_struct{ //这样就不会说指针类型不确定了,因为类的参数类型定下来了,指针的类型也跟着定下来了。
typedef bool(*fun_ptr)(T *);
};
template<class T>
bool is_positive(T *a){
if(**a)return 1;
return 0;
}
void test3(){ //函数指针做参数
vector<D<int> *> vecD;
vecD.push_back(new D<int>(1));
vecD.push_back(new D<int>(2));
vecD.push_back(new D<int>(3));
vecD.push_back(new D<int>());
fun_ptr fp;
fp = is_positive<D<int>>;
vector<D<int> *>::iterator p1=
check_each(vecD.begin(),vecD.end(),fp);
Fun_ptr_struct<D<int>>::fun_ptr fp2;
fp2 = is_positive<D<int>> ;
vector<D<int> *>::iterator p2=
check_each(vecD.begin(),vecD.end(),fp2);
}
//一个有意思的东西,让我们的函数对象用起来更精彩
class Base{
public:
virtual void do_something( )=0;
};
class Derive1:public Base{
public:
void do_something(){
cout<<"I am Derive1."<<endl;
}
};
class Derive2:public Base{
public:
void do_something(){
cout<<"I am Derive2."<<endl;
}
};
void test4(){
vector<Base *> vecB;
vecB.push_back(new Derive1);
vecB.push_back(new Derive2);
for_each(vecB.begin(),vecB.end(),mem_fun(&Base::do_something));
}
int main(){
test1();
test2();
test3();
test4();
}