Explanation of std::bind

1. Before explaining std::bind, let's review std::function first.

std::function is a "callable object" wrapper, a class template that can accommodate all callable objects except class member function pointers, which can handle functions, function objects, function pointers, and Allows saving and delaying their execution.

What is a callable object?

(1) Function pointer
(2) Class object with operator() member function (legendary functor), lambda expression
(3) Class object that can be converted into a function pointer
(4) Class member (function) pointer
( 5) bind expressions or other function objects

for example:

// 普通函数
int add(int a, int b){return a+b;} 

// lambda表达式
auto mod = [](int a, int b){ return a % b;}

// 函数对象类
struct divide{
    int operator()(int denominator, int divisor){
        return denominator/divisor;
    }
};

Save the above types with std::function:

std::function<int(int ,int)>  a = add; 
std::function<int(int ,int)>  b = mod ; 
std::function<int(int ,int)>  c = divide(); 

Two, std::bind

The std::bind function can be thought of as a generic function adapter that takes a "callable object" and generates a new callable object that "fits" the argument list of the original object.

std::bind mainly has the following two functions:
(1) Bind the callable object and its parameters into an anti-function;
(2) Only bind some parameters, reducing the parameters passed in by the callable object.

1. Binding common functions

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

auto divide_half = std::bind (my_divide,_1,2);  
std::cout << fn_half(10) << std::endl; // 输出5

(1) The first parameter of bind is the function name. When an ordinary function is used as an actual parameter, it will be implicitly converted into a function pointer. So std::bind (divide,_1,2) is equivalent to std::bind (÷,_1,2);
(2) _1 represents a placeholder, located in <functional>, std::placeholders::_1;

2. Binding member functions

#include <functional>
#include <iostream>

using namespace std;

struct Foo {
    void sum(int n1, int n2)
    {
        std::cout << n1+n2 << std::endl;
    }

	static int StaticMember(int a) { 
        return 66 + a; 
    }

    int data = 10;
};

int main() {
    Foo foo;
    auto f = std::bind(&Foo::sum, &foo, 95, std::placeholders::_1);
    f(5); // 输出100
}

(1) When bind binds a class member function, the first parameter represents the pointer of the member function of the object, and the second parameter represents the address of the object.
(2) Must explicitly specify &Foo::sum, because the compiler will not implicitly convert the member function of the object into a function pointer, so you must add & before Foo::sum; (3) When using the pointer of the object member
function , it is necessary to know which object the pointer belongs to, so the second parameter is the address of the object &foo;

3. Binding static member functions

	auto fun2 = &Foo::StaticMember;
    cout<<fun2(3)<<endl;

4. Binding member variables

#include <functional>
#include <iostream>

using namespace std;

class TestClass4 {
public:
    TestClass4() : m_a(100)
    {}
	
public:
    int m_a;
};

int main() {
    TestClass4 test4;
    auto fun4 = std::bind(&TestClass4::m_a, std::placeholders::_1);

	int var = fun4(test4);
    std::cout<<var<<std::endl;
}

5. Binding functors

#include <functional>
#include <iostream>

using namespace std;

class TestClass5 {
public:
    TestClass5() = default;
	
    TestClass5(const TestClass5& obj) {
        std::cout<<"TestClass5 copy construct."<<std::endl;
    }
	
    void operator()(int a) {
        std::cout<<a<<std::endl;
    }
};

int main(){
    TestClass5 test5;
    auto fun5 = test5;
    fun5(2018);
}

6. When binding member functions, which methods will call the "copy constructor" first?

#include <functional>
#include <iostream>

using namespace std;

class TestClass {
public:
    TestClass(int a):m_a(a){}
    TestClass(const TestClass& obj) {
        m_a = obj.m_a + 100;
        std::cout<<"copy construct."<<std::endl;
    }
	
    int ClassMember(int a) {
	    std::cout<<" this:"<<this<<" :"<<&m_a<<" "<<m_a<<std::endl;
		return 55 + a; 
	}
	
    int ClassMember2(int a,char ch,float f) {
        std::cout <<ch <<" "<< f << " "<<a<<std::endl;
        return 55 + a;
    }
	
    static int StaticMember(int a) {
	    return 66 + a; 
	}

public:
    int m_a;
};;

int main(){
    TestClass test(67);
    std::cout<<"&test "<<&test<<" "<<test.m_a<<" &test.m_a "<<&test.m_a<<std::endl;
    std::cout<<"---------------------------------------------------------------------"<<std::endl;
	auto fun4 = std::bind(&TestClass::ClassMember, test, std::placeholders::_1); // 调用拷贝构造函数
	fun4(4);
	
	std::cout<<"---------------------------------------------------------------------"<<std::endl;
	auto fun5 = std::bind(&TestClass::ClassMember, &test, std::placeholders::_1); // 不调用拷贝构造函数
    fun5(5);
	
	std::cout<<"---------------------------------------------------------------------"<<std::endl;
	auto fun6 = &TestClass::StaticMember; // 不调用拷贝构造函数
    std::cout<<fun6(6)<<std::endl;
	
	std::cout<<"---------------------------------------------------------------------"<<std::endl;
    auto fun7 = std::bind(&TestClass::m_a, std::placeholders::_1); // 不调用拷贝构造函数
    std::cout<<fun7(test)<<" "<<test.m_a<<std::endl;
	
}

Results of the:

7. The problem of passing reference parameters

When you need to pass the object to the parameter in bind, you need to use ref or cref.

#include<iostream>
#include<functional>
 
using namespace std;
using namespace placeholders;
 
void alter(int &a, int b) {
    a = b;
}

int main() {
    int a = 5;
    auto f1 = bind(alter, a, _1);      //此处bind中的参数a只是a的一个拷贝,而不是a的引用
    f1(9);                           
    cout << a << endl;                //所以此处a仍为5
 
    auto f2 = bind(alter, ref(a), _1);  //使用ref可以将a的引用传递给bind
    f2(9);
    cout << a << endl;                //所以此处a变成了9
 
    return 0;
}
 
 

8. Pointer to member function

#include <iostream>
struct Foo {
    int value;
    void f1() { std::cout << "f1(" << this->value << ")\n"; }
    void f2() { std::cout << "f2(" << this->value << ")\n"; }
};

void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
    (foo1->*fun)();  // call fun on the object foo1
    (foo2->*fun)();  // call fun on the object foo2
}

int main() {
    Foo foo1{1};
    Foo foo2{2};

    apply(&foo1, &foo2, &Foo::f1);
    apply(&foo1, &foo2, &Foo::f2);
}

(1) Definition of member function pointer: void (Foo::*fun)(), actual parameter passed when calling: &Foo::f;

(2) fun is a class member function pointer, so the member function *fun must be obtained by dereferencing when calling, that is, (foo1->*fun)().

reference:

(1) std::function and std::bind in C++11

(2) Use of c++bind function

(3) Section 6 std::bind binder

(4) C++11 notes: std::bind and std::placeholders

Guess you like

Origin blog.csdn.net/mars21/article/details/131478845