zoukankan      html  css  js  c++  java
  • 第11课 std::bind和std::function(2)_std::bind绑定器

    1. 温故知新:std::bind1st和std::bind2nd

    (1)bind1st、bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数、仿函数等)的第1个或第2个参数上

    (2)函数的返回值是一个函数对象。它用于包装和改造传入的函数(或仿函数),并形成一个新的仿函数对象(是一个可调用对象

    (3)与旧的可调用对象相比,新的仿函数对象参数个数少了1个。(相当于给少掉的那个参数一个默认的值

    2. std::bind绑定器

    (1)首先,std::bind也是一个函数模板返回值是一个仿函数,也是可调用对象。它的作用与bind1st和bind2st类似,是这两个函数的加强版。但极大地提高了灵活性,可以完全替代bind1st和bind2nd。

    (2)bind的作用主要就是将可调用对象变成std::function对象(即仿函数对象),主要体现在两个方面。

      ①将多元的可调用对象与其参数一起绑定成一个仿函数对象。

      ②将多元(设参数个数为n)的可调用对象转成一元或(n-1)元的可调用对象,即只绑定部分参数

    (3)std::bind可以绑定的对象(注意bind的返回值是仿函数)

      ①普通函数(functions);

      ②函数对象(仿函数,function objects);

      ③类的成员函数(member functions。注意:_1必须是某个对象的地址

      ④类的数据成员(data members注意:_1必须是某个对象的地址

    【编程实验】std::bind初探

    #include <iostream>
    #include <vector>
    #include <functional>  // for std::bind
    #include <typeinfo>
    
    using namespace std::placeholders;  //让_1, _2, _3,...可见!
    using namespace std;
    
    //除法函数:x/y
    double my_divide(double x, double y)
    {
        return x / y;
    }
    
    struct MyPair
    {
        double a, b;
        MyPair(int a, int b):a(a), b(b)
        {
            
            cout << "MyPair(int a, int b)" << endl;
        }
        //注意成员函数的第1个参数是this!!!
        double mutiply(){return a * b;}
    };
    
    int main()
    {
        //1、绑定函数
        auto fn1 = bind(my_divide, 10, 2); //返回一个std::function类型的仿函数
        //function<double(void)> fn1 = bind(my_divide, 10, 2); //绑定完,fn1是无参,所以为void
        //cout << typeid(fn1).name() << endl;
        cout << fn1() << endl;
        
        auto fn2 = bind(my_divide, _1, 2); //my_divide的第2个参数绑定为2
        cout << fn2(10) << endl;     // 输出5
        //cout << fn2(10, 3) << endl;  // 输出仍然为5!
        
        auto fn3 = bind(my_divide, _2, _1);
        cout << fn3(10, 2) << endl; //输出:0.2。注意10为第1个参数,被绑到_1的位置,2绑到_2的位置
        
        auto fn4 = bind<int>(my_divide, _1, _2); //指定返回值为int型
        cout << fn4(10, 3) << endl;
        
        //2、绑定类的成员
        MyPair mp{10, 2}; //注意,mp是个聚合对象,可用{}直接初始化(虽无2个参数的构造函数)。
        
        auto ftor_memfn = bind(&MyPair::mutiply, _1); //成员函数,其实有个this指针,须放入_1
        cout << ftor_memfn(mp) << endl; //20,传入mp对象的地址(这里传的是引用)
        
        auto ftor_memdata = bind(&MyPair::a, mp); //传mp对象的副本,
        //auto ftor_memdata = bind(&MyPair::a, &mp); //传mp的地址
        cout << ftor_memdata() << endl;  //10
        ftor_memdata() = 100;  //mp副本的a值被改为100
        cout << mp.a << endl;  //10,mp本身的a值未被改变,仍为10
        cout << ftor_memdata() << endl;
        
        auto ftor_memdata2 = bind(&MyPair::b, _1);
        cout << ftor_memdata2(mp) << endl;  //2
        ftor_memdata2(mp) = 50;  //传mp的引用
        cout << mp.b << endl;    //由于按引用传递,b的值被改!
        cout << ftor_memdata2(mp) << endl;
        
        return 0;
    }

    3. 使用std::bind的注意事项

    (1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数是按值传递的

    (2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。注意,对于placeholder是按引用传递的

    (3)通过placeholder可以改变传参的顺序。同时如果放置了placeholder_x的占位符,当调用时就必须给足至少x个实参

    (4)bind的返回值是可调用实体,可以直接赋值给std::function对象

    (5)对于绑定的指针、引用类型的参数,使用者需要保证在可调用对象调用之前,这些参数是可用的。

    【编程实验】placeholder、组合使用bind函数

    #include <iostream>
    #include <vector>
    #include <algorithm>   //for count_if
    #include <functional>  // for std::bind
    
    using namespace std;
    using namespace std::placeholders;
    
    void output(int x, int y)
    {
        cout << x << ", " << y << endl;
    }
    
    int main()
    {
        auto out1 = bind(output, _1, 2);
        out1(1);  //输出:1, 2
        
        auto out2 = bind(output, 2, _1);
        out2(1);  //输出:2, 1
        
        auto out3 = bind(output, 2, _2);
        out3(1, 3); //输出2, 3(注意,第1个参数被默认的2取代了)
        //out3(1);  //error, 调用时需给出第2个参数
        
        auto out4 = bind(output, 2, _2);
        out4(1, 3); //输出2, 3
        //out4(1);  //error, 调用时需给出第2个参数
        
        auto out5 = bind(output, _2, _1);
        out5(1, 3); //输出3, 1(第1个实参对应_1,第2个实参对应_2)
        
        vector<int> v{15, 37, 94, 50, 73, 58, 28, 98};
        
        //通过bind2nd绑定
        int n = count_if(v.begin(), v.end(), not1(bind2nd(less<int>(), 50)));
        cout <<"n = " << n << endl; //5(大于等于50的元素个数)
        
        //通过bind绑定
        auto fn = bind(less<int>(), _1, 50);
        cout << count_if(v.begin(), v.end(), fn) << endl; //3,小于50的元素个数
        cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, 50)) << endl; //3
        
        //组合使用bind
        //查找(50,73]之间的元素个数
        auto f = bind(logical_and<bool>(), bind(greater<int>(), _1, 50), bind(less_equal<int>(), _1, 73));
        cout << count_if(v.begin(), v.end(), f) << endl; //2
        
        return 0;
    }
  • 相关阅读:
    Java中extends和implements区别【杭州多测师】【杭州多测师_王sir】
    以下字符串,如果单词以辅音字母开头,则把辅音字母挪到最后,并在末尾加上“ay”。 如果以元音字母开头,则在末尾加上“hay”。 元音字母是“a.e.i.o.u” 字符串是“My name is Shopline,and i am 2,0000 days old”【杭州多测师】【杭州多测师_王sir】
    Linux环境下,请用一条命令计算出request.log文件中所有包含“requestDate”但是不包含“error”的行数【杭州多测师】【杭州多测师_王sir】
    主机重启hosts配置失效原因
    DNS BIND区域数据文件
    dns主从及智能dns搭建
    nginx 添加免费https证书
    nginx变量参数
    nginx last break详解
    常用工具下载地址
  • 原文地址:https://www.cnblogs.com/5iedu/p/7634477.html
Copyright © 2011-2022 走看看