第11课 std::bind和std::function_std::bind绑定器

Posted 浅墨浓香

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第11课 std::bind和std::function_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;
}

 

以上是关于第11课 std::bind和std::function_std::bind绑定器的主要内容,如果未能解决你的问题,请参考以下文章

C++11新特性应用--实现延时求值(std::function和std::bind)

C++11之用std::function和std::bind实现观察者模式

C++11 std::bind函数,std::function函数

C++11 std::bind std::function 变参函数

C++11 std::bind std::function 变参函数

C++11 std::bind和std::function解析