C++11 practical technology (2) std::function and bind binder

C++ Advanced Series Catalog

Use of C++ operator keywords (overloaded operators, functors, type conversion operators)

C++11 practical technology (1) the use of auto and decltype

C++11 practical technology (2) std::function and bind binder

C++11 Practical Technology (3) std::future, std::promise, std::packaged_task, async

Introduction

C++11 adds std::function and std::bind. Used for function wrapping and parameter binding. It can replace some function pointers and callback function scenarios.

std::function

std::function object wrapper

std::function is a wrapper for callable objects, which can be used to handle functions, function objects, and function pointers in a uniform way, and allows saving and deferred execution of them. It is more difficult to understand, you can go deeper from the code:

#include <iostream>
#include <functional>

void func(void)
{
    
    
	std::cout << __FUNCTION__ << std::endl;
}

class Foo
{
    
    
public:
	static int foo_func(int a)
	{
    
    
		std::cout << __FUNCTION__ << " :input param:" << a << std::endl;
		return a;
	}
};
class Bar
{
    
    
public:
	int operator()(int a)
	{
    
    
		std::cout << __FUNCTION__ << " :input param:" <<a<< std::endl;//
		return a;
	}
};
int main()
{
    
    
	std::function<void(void)> fr1 = func;//绑定普通函数
	fr1();

	std::function<int(int)> fr2 = Foo::foo_func;//绑定一个类的静态成员函数
	std::cout << "result:"<< fr2(123) << std::endl;

	Bar bar;
	std::function<int(int)> fr3 = bar;//绑定一个仿函数
	//fr2 = bar;//这里用fr2也可以,因为这两个函数的返回值和参数表是一样的
	std::cout << "result" <<fr3(123) << std::endl;
	return 0;
}

Note: __FUNCTION__ in the code is a predefined identifier, and its basic function is to return the name of the function where it is located, which is convenient for debugging log printing.

Running results:
insert image description here
It can be seen that by using the corresponding function return value and function parameter table assigned to std::function, it can accommodate functions of this type of calling method, which is called a "function wrapper". fr2 as above can hold Foo::foo_func and bar.
It can be seen here that function is similar to the function of a function pointer, and can store various types of function addresses.

std::function as callback function

#include <iostream>
#include <functional>

class A
{
    
    
	std::function<void(int)> callback_;
public:
	A(const std::function<void(int)>& f) : callback_(f) {
    
    }
	void notify(int a)
	{
    
    
		callback_(a);
	}
};
class Foo
{
    
    
public:
	void operator()(int a)
	{
    
    
		std::cout << __FUNCTION__  <<" a:" << a << std::endl;
	}
};
int main()
{
    
    
	Foo foo;
	A aa(foo);
	aa.notify(111);
	return 0;
}

It can be seen here that function can replace the function of function pointer, and function can be used to save the delayed execution of the function, so it is more suitable for use in the callback function scenario.

std::bind binder

std::bind can bind a callable object and its parameters together, and the bound result can be saved with std::function.
The way of binding ordinary functions and binding member functions is different.

bind binds ordinary functions

#include <iostream>
#include <functional>

void input(int x)
{
    
    
	std::cout << x << std::endl;
}

int main()
{
    
    
	std::function<void(int)> fr = std::bind(input, std::placeholders::_1);
	auto fr1 = std::bind(input, std::placeholders::_1);//这里用auto接收也行
	fr(2);
	fr1(3);
	return 0;
}

Among them, std::placeholders::_1 is a placeholder, indicating that this position will be replaced by the first parameter passed in when the function is called.

How to use placeholders :

#include <iostream>
#include <functional>

void input(int x, int y)
{
    
    
	std::cout << x << " " << y << std::endl;
}

int main()
{
    
    
	std::function<void(int, int)> fr = std::bind(input, std::placeholders::_1, 2);//这里用auto接收也行
	fr(4, 5);//4 2
	fr = std::bind(input, 2, std::placeholders::_1);
	fr(4, 5);//2 4
	fr = std::bind(input, std::placeholders::_1, std::placeholders::_2);
	fr(4, 5);//4 5
	fr = std::bind(input, std::placeholders::_2, 2);
	fr(4, 5);//5 2
	fr = std::bind(input, 2, std::placeholders::_2);
	fr(4, 5);//2 5
	return 0;
}

Result:
insert image description here
When binding parameters, the placeholder std::placeholders can be used to determine which parameter the empty space parameter will belong to when the call occurs.

bind bind member function

bind can bind member functions and member variables. There are some differences between binding member functions and binding ordinary functions.

#include <iostream>
#include <functional>

class MyClass {
    
    
public:
	int i_ = 0;
	void foo(int a, int b) {
    
    
		std::cout << a << " " << b << std::endl;
	}
};

int main() {
    
    
	MyClass obj;
	auto boundFunc = std::bind(&MyClass::foo, &obj, std::placeholders::_1, std::placeholders::_2);//绑定成员函数
	boundFunc(3, 4);
	auto fr_i = std::bind(&MyClass::i_, &obj);//绑定成员变量
	fr_i() = 123;

	return 0;
}

When using std::bind to bind member functions, you need to pay attention to the following points:

  • A pointer to a member function or a function object is required for binding. For pointers, you need to use the & addressing symbol to get the address of the member function.
  • A pointer (or reference) to the object needs to be provided as the first argument so that the member function is called correctly when invoked.

You can see that there is no need to provide pointers or references to objects as parameters when binding ordinary functions.

Guess you like

Origin blog.csdn.net/weixin_44477424/article/details/132125248