zoukankan      html  css  js  c++  java
  • STL基础--仿函数(函数对象)

    1 首先看个仿函数的例子

    class X {
       public:
       void operator()(string str) {     // 函数调用运算符,返回类型在operator之前
          cout << "Calling functor X with parameter " << str<< endl;
       }  
        operator string () const { return "X"; } //类型转换函数,返回类型在operator之后
    };
    
    int main()
    {
       X foo;
       foo("Hi");    // 以参数HI调用仿函数X
    }
    /*
     * 仿函数的好处:
     * 1. 智能函数: 比常规函数有更多的功能,比如可以保存状态(参数化的函数)
     * 2. 有它自己的类型,不用考虑函数重名问题
     * 事实上,类带来的其他好处,封装,继承,多态都可以是仿函数的好处
     */
    

    2 参数化的函数

    class X {
       public:
       X(int i) {}
       void operator()(string str) { 
          cout << "Calling functor X with parameter " << str<< endl;
       }
    };
    
    int main()
    {
       X(8)("Hi");
    }
    
    // 为什么需要参数化函数,用2个参数的函数代替不行么?
    
    
    // 只实现+2的功能,如果我想实现加任何数的功能
    void add2(int i) {
       cout << i+2 << endl;
    }
    
    // 用全局变量,显然不好
    // 用模板实现,加任何值的功能,但是val需要编译时常数
    template<int val>
    void addVal(int i) {
       cout << val+i << endl;
    }
    
    // 轮到仿函数登场了
    class AddValue {
       int val;
       public:
       AddValue(int j) : val(j) { }
       void operator()(int i) {
          cout << i+val << endl;
       }
    };
    
    int main()
    {
       vector<int> vec = { 2, 3, 4, 5};   
       //for_each(vec.begin(), vec.end(), add2); // {4, 5, 6, 7}
       int x = 2;
       //for_each(vec.begin(), vec.end(), addVal<x>); // {4, 5, 6, 7} ,编译不过
       for_each(vec.begin(), vec.end(), AddValue(x)); // {4, 5, 6, 7}
    }
    

    3 内置的仿函数

    // 比较 less greater  greater_equal  less_equal  not_equal_to
    // 逻辑 logical_and  logical_not  logical_or
    // 算术 multiplies minus  plus  divide  modulus  negate
    
    int x = multiplies<int>()(3,4);  //  x = 3 * 4 
    
    if (not_equal_to<int>()(x, 10))   // if (x != 10)
       cout << x << endl;
    

    4 参数绑定

    set<int> myset = { 2, 3, 4, 5};   
    vector<int> vec;
    
    
    int x = multiplies<int>()(3,4);  //  x = 3 * 4 
    
    // 将元素值乘以10,保存在vec中:
    transform(myset.begin(), myset.end(),    // 源
    	      back_inserter(vec),              // 目的
    			bind(multiplies<int>(), placeholders::_1, 10));  // 仿函数
        // multiplies<int>()的第1个参数替换为myset中的元素值
        // vec: {20, 30, 40, 50}
    
    
    void addVal(int i, int val) {
       cout << i+val << endl;
    }
    for_each(vec.begin(), vec.end(), bind(addVal, placeholders::_1, 2));
    
    // C++ 03: bind1st, bind2nd
    

    5 将常规函数转为仿函数

    double Pow(double x, double y) {
    	return pow(x, y);
    }
    
    int main()
    {
      set<int> myset = {3, 1, 25, 7, 12};
      deque<int> d;
      auto f = function<double (double,double)>(Pow);   //C++ 11
      transform(myset.begin(), myset.end(),     // 源地址
    		      back_inserter(d),              // 目的
    				bind(f, placeholders::_1, 2));  // 仿函数
                //  d: {1, 9, 49, 144, 625}
    }
    // C++ 03中使用ptr_fun 
    

    6 lambda函数

    // 想拷贝5<x<20之间的元素到d
    set<int> myset = {3, 1, 25, 7, 12};
    deque<int> d;
    
    // 定义一个函数
    bool needCopy(int x){
       return (x>20)||(x<5);
    }
    // 或者用内置仿函数和bind结合
    // 两种方法都不方便
    
    transform(myset.begin(), myset.end(),     // source
              back_inserter(d),               // destination
              needCopy
              );
    
    /*
              bind(logical_or<bool>, 
                  bind(greater<int>(), placeholders::_1, 20),
                  bind(less<int>(), placeholders::_1, 5))
    */
    
    // C++ 11 lambda function:
    transform(myset.begin(), myset.end(),     // source
              back_inserter(d),              // destination
              [](int x){return (x>20)||(x<5);}    //lambda函数
              );
    

    7 为什么STL中需要仿函数?

    set<int> myset = {3, 1, 25, 7, 12}; // myset: {1, 3, 7, 12, 25}
    // 同:
    set<int, less<int> > myset = {3, 1, 25, 7, 12};
    
    bool lsb_less(int x, int y) {
          return (x%10)<(y%10);
    }
    
    class Lsb_less {
       public:
       bool operator()(int x, int y) {
          return (x%10)<(y%10);
       }
    };
    int main()
    {
      set<int, Lsb_less> myset = {3, 1, 25, 7, 12};  // myset: {1,12,3,25,7}
      ...
    }
    

    8 谓词

     /*
     * 一种特殊的仿函数:
     * 1. 返回一个boolean值
     * 2. 不改变数据
     */
    
    class NeedCopy {
       bool operator()(int x){   
          return (x>20)||(x<5);  
       }
    };
    
    transform(myset.begin(), myset.end(),     // source
              back_inserter(d),               // destination
              NeedCopy()
              );
    
    // 谓词用于比较或者条件判断
    
  • 相关阅读:
    青云黄允松:2016年是云计算市场最关键的一年
    知道创宇CTO杨冀龙:网络安全人才决定行业格局
    su 与 su
    如何进入单用户模式(CentOS6.9)
    在虚拟机中还原GHO镜像系统
    安装CentOS 7 文字版
    把typora改为微软雅黑+Consolas
    使用python操作文件实现购物车程序
    使用python操作json文本文件
    资源下载网址集合
  • 原文地址:https://www.cnblogs.com/logchen/p/10200546.html
Copyright © 2011-2022 走看看