Callable object
In C++, there is a concept of “callable object”. To be precise, callable objects have the following definitions:
1. It is a function pointer
2. It is a class object (functor) with operator() member function
3. It is a class object that can be converted into a function pointer.
4. It is a class member (function) pointer
#include <iostream> using namespace std; void func(void) {} struct Foo { void operator()(void){} }; struct Bar { using fr_t = void(*)(void); static void func(void) { printf("%s %s %d\\ ", __FILE__, __func__, __LINE__); } operator fr_t(void) { return func; } }; struct A { int a_; void mem_func(void) { printf("%s %s %d\\ ", __FILE__, __func__, __LINE__); } }; int main() { void (*func_ptr)(void) = & amp;func; ///1. Function pointer func_ptr(); Foo foo; foo(); ///2. Functor Bar bar; bar(); ///3. Class object that can be converted into a function pointer void (A::*mem_func_ptr)(void) = & amp;A::mem_func; ///4. Class member function pointer int A::*mem_obj_ptr = & amp;A::a_; ///Class member pointer A aa; (aa.*mem_func_ptr)(); aa.*mem_obj_ptr = 123; return 0; }
As can be seen from the above, except for class member pointers, the objects involved in the above definition can be called like a function.
In C++11, these objects like in the above example (func_ptr, foo, bar, mem_func_ptr, mem_obj_ptr) are called callable objects. Correspondingly, the types of these objects are collectively called “callable types”.
C++11 now unifies the respective operations of callable objects through std::function and std::bind.
Callable object wrapper—std::function
std::function is a wrapper around a callable object. It is a class template that can hold all callable objects except class member (function) pointers. By specifying its template parameters, it can handle functions, function objects, and function pointers in a unified way, and allows saving and delaying execution of them.
Basic usage of std::function
#include <iostream> #include <functional> using namespace std; void func(void) { cout << __FUNCTION__ << endl; } classFoo { public: static int foo_func(int a) { cout << __FUNCTION__ << "(" << a << ") ->: "; return a; } }; class bar { public: int operator()(int a) { cout << __FUNCTION__ << "(" << a << ") ->: "; return a; } }; int main() { function<void(void)> fr1 = func; ///Bind a normal function fr1(); ///Bind a static member function of a class std::function<int(int)> fr2 = Foo::foo_func; cout << fr2(123) << endl; Bar bar; fr2 = bar; cout << fr2(123) << endl; return 0; }
The running results are as follows:
From the above we can see how to use std::function. When we fill in the appropriate function signature for std::function (i.e. a function type, which only needs to include the return value and parameter list), it becomes a A “function wrapper” that can accommodate all such calling methods.
Example of std::function as a callback function
#include <iostream> #include <functional> using namespace std; class A { public: A(const std::function<void()> & amp; f):callback_(f){} void notify(void) { callback_(); } private: std::function<void()> callback_; }; classFoo { public: void operator()(void) { cout << __FUNCTION__ << endl; } }; int main() { Foo foo; A aa(foo); aa.notify(); return 0; }
As you can see from the above example, std::function can replace the role of function pointers. Because it can save delayed execution of functions, it is more suitable as a callback function.
std::function as function parameter example
#include <iostream> #include <functional> using namespace std; void call_when_even(int x, const std::function<void(int)> & amp; f) { if (!(x & amp; 1)) { f(x); } } void output(int x) { cout << x << " "; } int main() { for(int i = 0; i < 10; i + + ) { call_when_even(i, output); } cout << endl; return 0; }
As you can see from the above example, std::function is more flexible and convenient than ordinary function pointers.
std::bind binder
std::bind is used to bind a callable object with its parameters. The result after binding can be saved using std::function and delayed calling until whenever we need it.
Generally speaking, it has two main functions:
1. Bind the callable object and its parameters into a functor.
2. Convert a multi-element (number of parameters is n, n>1) callable object into a one-element or (n-1) element callable object, that is, only bind some parameters.
Basic usage of std::bind
#include <iostream> #include <functional> using namespace std; void call_when_even(int x, const std::function<void(int)> & amp; f) { if (!(x & amp; 1)) { f(x); } } void output(int x) { cout << x << " "; } void output_add_2(int x) { cout << x + 2 << " "; } int main() { { auto fr = std::bind(output, std::placeholders::_1); for(int i = 0; i < 10; i + + ) { call_when_even(i, fr); } cout << endl; } { auto fr = std::bind(output_add_2, std::placeholders::_1); for(int i = 0; i < 10; i + + ) { call_when_even(i, fr); } cout << endl; } return 0; }
We use std::bind to control the final execution result by binding different functions outside the function.
We use auto fr to save the return result of std::bind, because we don’t care about the real return type of std::bind (in fact, the return type of std::bind is a functor type defined internally by stl), we only need to know it Is a functor that can be directly assigned to a std::function. Of course, it is also possible to directly use the std::function type to save the return value of std::bind.
std::placeholders::_1 is a placeholder, which means that this position will be replaced by the first parameter passed in when the function is called.
Placeholder for std::bind
#include <iostream> #include <functional> using namespace std; void output(int x, int y) { cout << x << " " << y << endl; } int main() { ///Output 1,2 std::bind(output, 1, 2)(); ///Output 2,2 std::bind(output, std::placeholders::_1, 2)(2); ///Output 3,444 std::bind(output, 3, std::placeholders::_1)(444); ///error, there is no second parameter when calling ///std::bind(output, 3, std::placeholders::_2)(333); ///The first parameter is swallowed when calling ///Input 1, 333 std::bind(output, 1, std::placeholders::_2)(7, 333); ///Enter 7, 333 std::bind(output, std::placeholders::_1, std::placeholders::_2)(7, 333); return 0; }
The above method calls the return result of std::bind directly. As you can see, std::bind can directly bind all parameters of the function, or it can also bind some parameters.
When binding some parameters, std::placeholders are used to determine which parameter the empty parameter will belong to when the call occurs.
std::bind and std::function are used together
#include <iostream> #include <functional> using namespace std; class A { public: int i_ = 0; void output(int x, int y) { cout << x << " " << y << endl; } }; int main() { A a; std::function<void(int, int)> fr = std::bind( & amp;A::output, & amp;a, std::placeholders::_1, std::placeholders::_2); fr(1, 2); std::function<int & amp; (void)> fr_i = std::bind( & amp;A::i_, & amp;a); fr_i() = 123; cout << a.i_ << endl; return 0; }
The type of fr is std::function
After that, std::bind binds the pointer of member i_ of A to a, and the returned result is stored in std::function