zoukankan      html  css  js  c++  java
  • STL源码解析之bind1st和bind2nd

    首先我们先来了解一下一元函数和二元函数。
    一元函数数学上一般形式表示为 z = f(x),只有一个变量x。
    二元函数数学上一般形式表示为 z = f(x,y),存在两个变量,分别是x和y。

    STL中为了描述一元函数和二元函数,定义了两个结构体来描述。如下:

    //一元函数结构
    template <class Arg, class Result>
    struct unary_function 
    {
        typedef Arg argument_type; //参数类型,可以理解为x对应的类型
        typedef Result result_type;//返回值类型,可以理解为 z 对应的类型
    };
    //二元函数结构
    template <class Arg1, class Arg2, class Result>
    struct binary_function
     {
        typedef Arg1 first_argument_type; //第一个参数类型,可以理解为x对应的类型
        typedef Arg2 second_argument_type;//第二个参数类型,可以理解为y对应的类型
        typedef Result result_type; //返回值类型,可以理解为 z 对应的类型
    };

    接下来我们来看看,一元函数结构和二元函数结构在STL中用来定义实际一元函数和二元函数的例子,如下

    //取负
    template <class T>
    struct negate : public unary_function<T, T> {
        T 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; }
    };

    知道了STL中一元函数和二元函数的具体实现,我们就可以来看下bind1st的具体定义,如下:

    template <class Operation, class T>
    inline binder1st<Operation> bind1st(const Operation& op, const T& x) 
    {
        typedef typename Operation::first_argument_type arg1_type;
        return binder1st<Operation>(op, arg1_type(x));
    }

    参数op为Operation类型的函数对象,参数x为类型T的对象,而bind1st函数的返回值实际是构造了一个binder1st的对象。
    那我们接着看下binder1st的具体定义,源码如下:

    template <class Operation>
    class binder1st: public unary_function<typenameOperation::second_argument_type,typename Operation::result_type>
    {
    protected:
        Operation op;//代表操作语义的二元函数对象,可以理解为上文中的函数f
        typename Operation::first_argument_type value;//绑定的参数类型对应的对象
    public:
        binder1st(const Operation& x,const typenameOperation::first_argument_type& y) : op(x), value(y) {}
        typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const 
      {   
    return op(value, x);   } };

    由此我们可以看出bind1st(op,value);实际是构造了一个binder1st类的对象,对应的操作是op,绑定值value,

    binder1st类重载函数调用操作符(),实际调用的时候相当于binder1st(op,value)(x);从上面重载的实际实现我们可以看出,
    这个实际上就是op(value,x);即绑定了value值作为二元函数op的第一个参数,而此时x变量为第二个参数。

    bind2nd的源码如下:

    template <class Operation, class T>
    inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) 
    {   typedef typename Operation::second_argument_type arg2_type;   
    return binder2nd<Operation>(op, arg2_type(x)); }

    实际就是构造一个binder2nd对象,而binder2nd的实现如下:

    template <class Operation>
    class
    binder2nd : public unary_function<typename Operation::first_argument_type, typename Operation::result_type>
    {
    protected:   Operation op;   typename Operation::second_argument_type value; public:   binder2nd(const Operation& x,const typename Operation::second_argument_type& y)   : op(x), value(y) {}   typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const
      {     
    return op(x, value);   } };

    对照上面对binder1st类的描述,实际bind2nd(op,value);的形式等价于binder2nd(op,value);而实际调用的形式
    binder2st(op,value)(x);就等价于op(x,value);

    下面通过一个例子来区分一下,bind1st和bind2nd在使用上区别。

    我们要从一个存放学生成绩的容器中分别统计分数大于等于60分的个数,以及小于60分的学生个数。
    我们讲通过STL里面的条件统计函数count_if和二元函数来完成上面的要求。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    
    using namespace std;
    
    int main()
    {
         vector<int> vec ;
         vec.push_back(40);vec.push_back(50);
         vec.push_back(60);vec.push_back(70);
         vec.push_back(80);vec.push_back(90);
        
         //统计及格个数
         binder1st<less_equal<int> > binder1 = bind1st(less_equal<int>(),60);//==>binder1st(less,60);
         int nPassCnt = count_if(vec.begin(), vec.end(), binder1 );//==>less_equal(60,x)==> 60 <= x
             
         //统计不及格个数
         binder2nd<less<int> > binder2 = bind2nd(less<int>(), 60);//==>binder2nd(less,60);
         int nFailCnt = count_if(vec.begin(), vec.end(), binder2 );//==>less(x,60);==> x < 60
             
         cout << "nPassCnt:"  << nPassCnt << endl;
         cout << "nFailCnt:"  << nFailCnt << endl;
        
         return 0;
    }

    运行结果:

    nPassCnt:4
    nFailCnt:2

  • 相关阅读:
    中途接手一个项目时候,需要注意
    PPT做交互效果
    hyperledger学习资料
    k8s拾遗
    Day0-3. 部署docker镜像私有仓库harbor
    Day0-2. Docker安装部署
    Day0-1. Docker环境准备
    【转载】轻量级HTTP服务器Nginx(Nginx性能优化技巧)
    使用nginx-module-vts监控各虚拟主机的流量
    Linux系统下终端proxy代理配置
  • 原文地址:https://www.cnblogs.com/chuyongliu/p/5308616.html
Copyright © 2011-2022 走看看