函数对象
如果f是一个function object,则可以将operator()作用于f身上。他是一个行为类似于函数的对象,为了能够行为类似函数,其类别中必须定义(或重载、重写)function call运算符(operator()),就可以在函数对象后加一对小括号以此来调用函数对象定义的operator()。
调用函数对象时构造函数和operator()执行顺序
- 首先执行构造函数,构造出一个匿名对象
- 然后在执行operator(),产生函数行为
#include <iostream> #include <vector> #include <algorithm> #include <string.h> #include <iterator> using namespace std; class F1 { public: F1(string t):s1(t) { cout<<" 带参构造函数"<<endl; } F1() { cout<<" 无参构造函数"<<endl; } bool operator()(string s) { cout<<" operator()函数"<<endl; return strcmp(s.c_str(),s1.c_str()); } private: string s1; }; int main() { vector<string> vs{"hello"," ","word","!","how"," ","you","."}; //1.F1 f1("you");被解析为f1.operator(arg); F1 f1("you"); remove_copy_if(vs.begin(),vs.end(),ostream_iterator<string>(cout,"\n"),f1); cout<<"****************************************"<<endl; //2. remove_copy_if(vs.begin(),vs.end(),ostream_iterator<string>(cout,"\n"),F1("you")); cout<<"****************************************"<<endl; //3. F1()("hello");//这是一个函数调用的行为 return 0; }
函数对象可以有自己的状态,也可以与函数配接器搭配使用。
template<typename T, T add> struct m_plus { m_plus() { _add = add; } T operator()(const T& x) { return x + _add; } // 仿函数可以具有自己的状态 int _add; };
为了能够拥有配接能力,每一个仿函数必须定义自己的响应型别。这些型别是为了让配接器能够取出,获得仿函数的某些信息。
unary_function
来反应一元仿函数的参数型别和返回值型别。
//一元仿函数 template <class Arg,class Result> struct unary_function{ typedef Arg argument_type; typedef Result result_type; };
binary_function
来反应二元仿函数的第一参数型别第二参数型别返回值型别。
//二元仿函数 template <class Arg1,class Arg2,Class Result> struct binary_function{ typedef Arg1 firs_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; };
算数类仿函数
template <class T> struct plus:public binary_function<T,T,T>{ T operator()(const T & x,const T & y) const {return x + y;} }; template <class T> struct minus:public binary_function<T,T,T>{ T operator()(const T & x,const T & y) const {return x - y;} }; tmeplate<class T> struct muliplies:public binary_function<T,T,T>{ T operator()(const T & x,const T & y) const {return x * y;} }; tmeplate<class T> struct divides:public binary_function<T,T,T>{ T operator()(const T & x,const T & y) const {return x / y;} }; tmeplate<class T> struct modulus:public binary_function<T,T,T>{ T operator()(const T & x,const T & y) const {return x % y;} }; tmeplate<class T> struct negate:public unary_function<T,T>{ T operator()(const T & x) const {return -x;} };
证同元素
意思是数值A若与该元素做op运算,会得到A自己。例如加法的证同元素是0,任何元素加上0都是自己本身。乘法的证同元素是1,任何元素乘1都为元素本身。
template<class T> inline T identity_element(plus<T>) {return T(0);} template<class T> inline T identity_element(multiplies<T>) {return T(1);}
逻辑运算符仿函数
他们都继承与二元仿函数。
template<class T> struct logical_and:public binary_function<T,T,bool>{ bool operator()(const T & x,const T & y) const {return x&&y;} }; template<class T> struct logical_or:public binary_function<T,T,bool>{ bool operator()(const T & x,const T & y) const {return x||y;} }; template<class T> struct logical_not:public unary_function<T,bool>{ bool operator()(const T & x) const {return !x;} };
证同(identity)、选择(select)、投射(project)
//证同函数。任何数值通过此函数后,不会有任何改变 //此式运用于<stl_set.h>,用来指定RB-tree所需的KeyOfValue op //set元素键值即实值,所以采用identity template <class T> struct identity : public unary_function<T,T>{ const T& operator()const T& x) const { return x; } }; //选择函数:接收一个pair,返回其第一元素 //此式运用于<stl_map.h>,用来指定RB-tree所需的KeyOfValue op //由于map系以pair元素的第一元素为其键值,所以采用select1st template <class Pair> struct select1st : public unary_function<Pair,typename Pair::first_type> { const typename Pair::first::first_type& operator()(const Pair& x)const{ return x.first; } }; //选择函数:接收一个Pair,传回其第二元素 //SGI STL未运用此式 template <class Pair> struct select2nd : public unary_function<Pair,typename Pair::second_type> { const typename Pair::first::second_type& operator()(const Pair& x)const{ return x.second; } }; //投射函数:传回第一参数,忽略第二参数 //SGI STL未运用此式 template<class Arg1,class Arg2> struct project1st : public binary_function<Arg1,Arg2,Arg1>{ Arg1 operator()(const Arg1& x,const Arg2&)const{ return x; } }; //投射函数:传回第二参数,忽略第一参数 //SGI STL未运用此式 template<class Arg1,class Arg2> struct project2nd : public binary_function<Arg1,Arg2,Arg2>{ Arg1 operator()(const Arg1&,const Arg2& y)const{ return y; } };