C++ 11 std::function and std::bind

  • 2020-07-21 09:40:46
  • OfStack

After cocos new published a new project, it was only after careful reading of the code that I found one sentence of the difference between 3.0 and 2.0:


auto closeItem = MenuItemImage::create(
                      "CloseNormal.png",
                      "CloseSelected.png",
                          CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

The code in 2.0 USES menu_selector instead of CC_CALLBACK_1.

The CC_CALLBACK series is a new addition to 3.0 based on c++11 features. The CC_CALLBACK series is defined as follows:


// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

As can be seen, the number after CC_CALL_BACK system represents the number of arguments to the function pointer. With this in mind, when you select CC_CALLBACK, you will not make an error.

When you look at the sample code, there is another interesting use:


listener->onTouchesBegan = CC_CALLBACK_2(Layer::onTouchesBegan, this);

So what is onTouchesBegan? Why can't you just assign a function pointer to it?

Just look at the definition


std::function<void(const std::vector<Touch*>&, Event*)> onTouchesBegan;

Because the CC_CALLBACK series is std::bind and onTouchesBegan is defined by std::function. So what's the difference between std::bind and std::function?

One blog post said:

The function template class and bind template functions provide functionality similar to a function pointer, but more flexible than a function pointer, especially if the function points to a non-static member of the class.

std::function can be bound to global functions/static-like member functions (there is no difference between static-like member functions and global functions). To bind to non-static member functions of a class, you need to use std::bind.

The standard library functions bind() and function() are defined in header files < functional > (this header file also includes many other function objects) for handling functions and function arguments.

std: : bind binder

Converts functions, member functions, and closures to function function objects Multivariate (n > 1) Convert the function to a meta-function or (ES74en-1) meta-function.

bind() accepts 1 function (or function object, or whatever you can pass "(...) Generates a function object that has one or more function parameters that are "bound" or reorganized. As the name implies, the bind() function is like its function name 1 and is used to bind certain parameters to a function call. Such as:


int f(int, char, double);
auto ff = bind(f, _1, 'c', 1.2);   //  The binding f() The number of the function call 2 And the first 3 Parameter, return 1 A new function object is ff It only carries 1 a int Parameter of type 
int x = ff(7);            // f(7, 'c', 1.2);

The binding of the parameter is often referred to as "Currying" and "_1" is a placeholder object for the position of the first parameter of the function ff in the parameter list of the function f when the function ff is called through the function ff. The first parameter is called "_1", the second parameter is "_2", and so on. Such as:


int f(int, char, double);
auto frev = bind(f, _3, _2, _1);    //  Flip parameter order 
int x = frev(1.2, 'c', 7);       // f(7, 'c', 1.2);

Here, the auto keyword saves us the work of inferring the type of results returned by bind.

We cannot bind the arguments of 1 overloaded function using bind(), we must explicitly indicate the version of the overloaded function we need to bind to:


int g(int);
double g(double);

auto g1 = bind(g, _1);             //  Error: call 1 a g() ?
auto g2 = bind( (double(*)(double))g, _1);  //  True, but rather ugly 


void H(int a);
// Bind global functions 
auto f11 = std::bind(H, std::placeholders::_1);
auto The type of theta is actually std::function<void(int)>

// Binds a member function with parameters 
std::function<void (char*, int)> f = std::bind(&ReadHandler::ConnectPreProcess, this, std::placeholders::_1, std::placeholders::_1);

//3 The meta-function is converted to 1 A function of 
int f(int, char, double);
//  The binding f() The number of the function call 2 And the first 3 The parameters, 
//  return 1 A new function object is ff It only carries 1 a int Parameter of type 
auto ff = bind(f, _1,  ' c', 1.2);  
int x = ff(7);

Write your own code examples as follows:


int Func(int x, int y);
auto bf1 = std::bind(Func, 10, std::placeholders::_1);
bf1(20); ///< same as Func(10, 20)

int HelloWorld::AddFunc( int a, int b )
{
  return a + b;
}

bool HelloWorld::init()
{

  auto bf2 = std::bind(&HelloWorld::AddFunc,this , std::placeholders::_1, std::placeholders::_2 );
  auto result1 = bf2(10, 20); ///< same as a.Func(10, 20)

  std::function< int(int)> bf3 = std::bind(&HelloWorld::AddFunc, this, std::placeholders::_1, 100);
  auto result2 = bf3(10); ///< same as a.Func(10, 100)

}

In the above example, bf1 binds the first parameter of a two-parameter ordinary function to 10, generating a new callable entity with one parameter. bf2 binds a class member function to a class object and generates a new callable entity like ordinary function 1. bf3 binds the class member function to the class object and the second parameter, generating a new std::function object. With the above examples in mind, here are 1 things to watch out for with bind:

(1) The pre-bound parameters of bind need to pass in specific variables or values. For the pre-bound parameters, it is pass-ES113en-ES114en
(2) For parameters not previously bound, std::placeholders should be passed in, starting from _1 and increasing in turn. placeholder pass - by - reference
(3) The return value of bind is a callable entity that can be directly assigned to the std::function object
(4) For the parameters of the binding pointer and reference type, the consumer needs to ensure that these parameters are available before the invocation of the callable entity
(5) this of class can be bound by objects or Pointers

std::function

It is a wrapper around functions, function objects, function Pointers, and member functions, and can hold any type of function object, function pointer, reference function, and member function pointer.
Handles functions, function objects, function Pointers, and member functions in a unified 1 manner. Allows saving and delaying execution of functions.

Functions and member functions as function
function is 1 to possess anything that can be taken with "(...)" "The type of value the symbol invokes. In particular, the return result of bind can be assigned to the function type. function10 is easy to use. More intuitively, think of function as a data type that represents functions, like function object 1. While ordinary data types represent data, function represents the abstract concept of functions.) Such as:


typedef std::function<float (int x, int y)> f ;//  structure 1 A function object, what it can represent 1 The return value is float , the two parameters are int . int The function of  
struct int_div {    //  structure 1 Can be used "()" The type of function object to call  
  float operator() (int x, int y) const { return ((float)x)/y; };
};

void HelloWorld::testing()
{
  f f1= int_div();          //  The assignment  
  auto result3 = f1( 10, 2);
}

A member function can be considered a free function with additional parameters:


// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
0

ps: cheated by vs2012's bug. Because if you look at the code on the web it starts at line 9: f_2 f2 = & int_div::int_div_fun;

Error 1 error C2664: 'std::_Func_class < _Ret,_V0_t,_V1_t > ::_Set' : cannot convert parameter 1 from '_Myimpl *' to 'std::_Func_base < _Rx,_V0_t,_V1_t > *'

Check 1, vs2010 does not have this compilation error, but 2012 does. To compile 2012 you must add std::mem_fn.

function can be used instead of function Pointers. Because it can hold a function for deferred execution, it is better used as a callback function, or it can be thought of as similar to the special delegate in c# with only one member.


// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
1

function can also be used as a function to control the internal behavior of a function from the outside, making our function more flexible.


// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
2

c++11 introduced function in order to generalize function object, function pointer, reference function, member function pointer, so that we can write more generalized code in a more uniform way; bind was introduced to replace and enhance the previous standard libraries bind1st and bind2st to make it easier to use


Related articles: