function函數回調+bind詳解

function函數回調+bind詳解


一.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;

}

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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章