STL 仿函数(一) bind函数回调


前言.C语言与C++中函数指针回顾

double divide(double x, double y) { return x / y; }

void test0()
{
    //C++
    function<double(double, double)> func1 = divide;
    cout << func1(10, 2) << endl;

    //C
    double (*func2)(double, double) = divide;
    cout << func2(12,3) << endl;
    
    typedef double(*Func)(double,double);
    Func func3 = divide;
    cout << func3(15,5) << endl;

}

一.bind函数适配器详解

1.function + bind 绑定普通函数

bind可以绑定函数中的参数再进行使用,比C语言中的更为方便。
同时需要注意:bind实质上是将函数入口进行了绑定

void test1()
{
  using namespace placeholders; 


  function<double()> func1 = bind(divide, 10, 2);
  cout << func1() << endl;

  function<double(double)> func2 = bind(divide, _1, 2);
  cout << func2(6) << endl;

  function<double(double)> func3 = bind(divide, 6, _1);
  cout << func3(1) << endl;

  function<double(double, double)> func4 = bind(divide, _1, _2);
  cout << func4(4, 2) << endl;

  auto func5 = bind<int>(divide, 12.5, 3); //相当于 (int)divide(12.5, 3)
  cout << func5() << endl;
}

2.绑定类中的成员

首先要明白,直接将类中的成员函数赋值给函数指针是行不通的,因为成员函数中有隐含的this指针,是无法一并传给函数指针的。
如果是直接想绑定类中的成员函数的话:
1). 要么这个函数必须是static修饰(这样的话成员函数就不再拥有this指针,可以直接传递给函数指针,指针指向函数入口)
2). 要么在bind该函数的时候将this指针一同传入(也就是传入一个实例化的类对象就可以了)

class myclass
{
public:
  double add(double x, double y)
  {
    return x + y;
  }
};

void test2()
{
  myclass my;
  //传入my的作用在于传入隐含的this指针
  function<double(double,double)> func1 = bind(&myclass::add, my, 2, 3);
  cout << func1(1,2) << endl;
}


struct myStruct
{
  double a, b;
  double add()
  {
    return a + b;
  }
};


//需要注意,func() 与 function<> 里面的参数个数,类型必须相同的,不能因为绑定了就少写
void test3(){
  myStruct my{1,2};
  //func1调用成员函数add
  function<double()> func1 = bind(&myStruct::add, my);
  cout << func1() << endl;
  
  //此时的this指针是通过转递的方式, 而不是通过绑定的方式,反正只要传入this指针就行了,func2调用成员函数add
  function<double(myStruct)> func2 = bind(&myStruct::add, placeholders::_1);
  cout << func2(my) << endl;

  //输出myStruct中的a, func3调用成员变量a
  function<double(myStruct)> func3 = bind(&myStruct::a, my);
  cout << func3(my) << endl;
}

3. cref,ref与bind结合使用

ref可以理解为传入引用
cref 则是const reference

void f(int& n1, int& n2, const int& n3)
{
    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    ++n1; // increments the copy of n1 stored in the function object
    ++n2; // increments the main()'s n2
    // ++n3; // compile error
}
 
void test4()
{
    int n1 = 1, n2 = 2, n3 = 3;
    std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
    n1 = 10;
    n2 = 11;
    n3 = 12;
    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    bound_f();
    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

二.没有继承关系的情况下使用bind实现多态

Figure, Rectangle Circle 没有继承关系的类 实现多态
利用 bind 回调函数, Figure基类中注册回调函数,实现多态时再进行调用就可以了,本质上是属于bind注册回调函数。

#include <iostream>
#include <functional>
#include <vector>
#include <iterator>
#include <algorithm>
#include <unordered_map>
#include <functional>
#define pi 3.1415926
using namespace std;

typedef function<void()> figureCallBack;
typedef function<double()> areaCallBack;

class Figure
{
public:
    void setfigureFunc(figureCallBack cb1)
    {
        _cb1 = cb1;//注册回调函数
    }

    void setareaFunc(areaCallBack cb2)
    {
        _cb2 = cb2;//注册回调函数
    }

    void displayFigure()
    {
        _cb1();
    }
    double displayArea()
    {
        _cb2();
    }

private:
    figureCallBack _cb1;
    areaCallBack _cb2;
};

class Rectangle
{
public:
    Rectangle(int width, int length)
        : _width(width), _length(length)
    {
    }

    void displayFigure()
    {
        cout << "Rectangle" << endl;
    }
    double displayArea()
    {
        return _width * _length;
    }

private:
    int _width;
    int _length;
};


class Circle{
public:
    Circle(double radius)
    :_radius(radius)
    {

    }

    void displayFigure(){
        cout << "Circle" << endl;
    }

    double displayArea(){
        return pi * _radius * _radius; 
    }

private:
    double _radius;
};

void display(Figure &f)
{
    f.displayFigure();
    cout << "Area = " << f.displayArea() << endl;
}

int main()
{
    Rectangle rectangle(3, 4);
    Circle circle(2);
    Figure f;

    //矩形
    figureCallBack fn1 = bind(&Rectangle::displayFigure, &rectangle);
    areaCallBack fn2 = bind(&Rectangle::displayArea, &rectangle);
    f.setfigureFunc(fn1);
    f.setareaFunc(fn2);
    display(f);

    //圆形
    fn1 = bind(&Circle::displayFigure, circle);
    fn2 = bind(&Circle::displayArea, circle);
    f.setfigureFunc(fn1);
    f.setareaFunc(fn2);
    display(f);
    return 0;
}

三.mem_fn函数 将成员函数转换为函数对象

struct MyStruct
{
    int val;
    void print()
    {
        cout << "this is print" << endl;
    }
    void printval(int i)
    {
        cout << "this is printval " << i << endl;
    }
};

void test1()
{
    MyStruct my{10};
    auto func1 = mem_fn(&MyStruct::print);
    func1(my); //传入my是因为必须传入this指针

    auto func2 = mem_fn(&MyStruct::printval);
    func2(my, 2);

    auto func3 = mem_fn(&MyStruct::val);
    cout << func3(my) << endl;
}


class Data{
public:
    Data(int data)
    :_data(data)
    {

    }

    void display(){
        cout << _data << endl;
    }

    

private:
    int _data;
};


void test2(){
    vector<Data> vec{Data(1), Data(2), Data(3)};
    for_each(vec.begin(), vec.end(), mem_fn(&Data::display));//因为本身就是在Data类的内部,所以不再需要传入this指针

}


四.bind结合算法

使用算法与函数结合的方法总结:

void display(int i)
{
    cout << i << endl;
}

struct Mydisplay{
    void display(int i ){
        cout << i << endl;
    }
    bool operator()(int i){
        cout << i << endl;
        return true;
    }
};


void test3()
{
    vector<int> vec{1, 2, 3, 4, 5};
    
    //1.使用Lambda表达式
    // for_each(vec.begin(), vec.end(), [](int x){cout << x << endl;});

    //2.使用普通函数
    //for_each(vec.begin(), vec.end(), display);
    
    //3.bind绑定普通函数
    // for_each(vec.begin(), vec.end(), bind(display, 1));

    //4.bind绑定类成员函数
    // Mydisplay my;
    // for_each(vec.begin(), vec.end(), bind(&Mydisplay::display, my, placeholders::_1));

    //5.使用函数对象
    // for_each(vec.begin(), vec.end(), Mydisplay());
}

五.function+bind综合程序



#include <functional>
#include <iostream>

struct Foo
{
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_ + i << '\n'; }
    int num_;
};

void print_num(int i)
{
    std::cout << i << '\n';
}

struct PrintNum
{
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};

int main()
{
    // store a free function
    std::function<void(int)> f_display = print_num;
    f_display(-9);

    // store a call to a member function
    std::function<void(const Foo &, int)> f_add_display = &Foo::print_add;
    const Foo foo(314159);
    f_add_display(foo, 1);

    //  store a call to a function object
    std::function<void(int)> f_display_obj = PrintNum();
    f_display_obj(18);

    // store the result of a call to std::bind
    std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    f_display_31337();

    // store a call to a member function and object
    using std::placeholders::_1;
    std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
    f_add_display2(2);

    // store a call to a member function and object ptr
    std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
    f_add_display3(3);
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值