首页 > 技术文章 > 函数对象

tianzeng 2018-04-03 23:10 原文

  如果f是一个function object,则可以将operator()作用于f身上。他是一个行为类似于函数的对象,为了能够行为类似函数,其类别中必须定义(或重载、重写)function call运算符(operator()),就可以在函数对象后加一对小括号以此来调用函数对象定义的operator()。

  调用函数对象时构造函数和operator()执行顺序

  1. 首先执行构造函数,构造出一个匿名对象
  2. 然后在执行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; }
};

 

推荐阅读