[Analysis of C++11] std::function and std::bind

Posted by JimD on Sat, 03 Aug 2019 05:46:30 +0200

Catalog

[Analysis of C++11] std::function and std::bind

std::function callable object wrapper

C++ Callable Objects are defined as follows:

  1. Function pointer: consistent with C language;
  2. Class member function pointer;
  3. Functor: a class/structure object that is also a function object, overloading the operator() operator;
  4. lambda expression.

std::function is a wrapper (Wrapper) for Callable Objects that can receive any Callable Objects except pointers to class member functions.std::function can be used to handle function callbacks, similar to C function pointers, allowing the above Callable Objects to be saved and deferred from execution, but it can save Callable Objects other than function pointers, so it is more powerful than C.

When we instantiate a function signature for std::function (function type, including return values and parameter lists), it becomes a function wrapper that holds all such calls.

std::function basic usage

#include <iostream>
#include <functional> // std::function

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

class Foo {
public:
  // class static function
  static int foo_func(int a) {
    std::cout << __FUNCTION__ << "(" << a << "):";
    return a;
  }

  // class non-static member function
  int foo_func_nonstatic(int a) {
    std::cout << __FUNCTION__ << "(" << a  << "):";
    return a;
  }
};

class Bar {
public:
  // functor
  int operator()(int a) {
    std::cout << __FUNCTION__ << "(" << a << "):";
    return a;
  }
};

int main() {
  // Bind the corresponding signature by passing in the appropriate function signature to the std::function template parameter
  // Ordinary function or
  // Class static member function or
  // With std::bind binding class nonstatic member function
  std::function<void(void)> func1 = func;
  std::function<int(int)> func2   = Foo::foo_func;
  Foo foo;
  std::function<int(int)> func3   = std::bind(&Foo::foo_func_nonstatic, &foo,
                                              std::placeholders::_1);

  // Then, call it directly like a function
  func1(); // func
  std::cout << func2(1)  << std::endl; // foo_func(1):1
  std::cout << func3(11) << std::endl; // foo_func_nonstatic(11):11

  // func2 can be reused as a variable when the function signatures are consistent
  // Bar overloads operator() and becomes a functor, which can be packaged directly into std::function
  Bar bar;
  func2 = bar;
  std::cout << func2(2) << std::endl; // operator()(2):2

  // lambda expressions can also be bound
  auto func_lambda = [](int a){
    std::cout << "bind lambda sample(" << a << ")" << std::endl;
  };
  func_lambda(3); // bind lambda sample(3)

  return 0;
}

Since std::function can be used as a left-value receiving function object, it can be used as a parameter of the function, and std::function can bind function pointers to delay the execution of the function, so std::function can replace std::function as a callback function.

std::function implements callback mechanisms as follows:

#include <iostream>
#include <functional> // std::function

// Any callable object, such as a general global function
void func_callback(int a) {
  std::cout << __FUNCTION__ << ":Output, a=" << a << std::endl;
}

class Foo {
public:
  explicit Foo(std::function<void(int)> cb)
    :cb_(cb), a_(0) {
  }
  ~Foo() = default;

  // setter
  void set_a(int a) {
    a_ = a;
  }

  void OutputCallback() {
    cb_(a_);
  }

private:
  std::function<void(int)> cb_;
  int a_;
};

int main() {
  // Instantiate Foo and inject parameters into callback functions
  // Handle
  // Callback Output Processing Results
  Foo foo(func_callback);
  foo.set_a(1);
  foo.OutputCallback(); // func_callback:Output, a=1

  return 0;
}

Above, the usage of std::function binding Callable Objects is introduced, and an example demonstrates std::function as an example of function callback; where the parameter of func_callback callback function is int type, in practical applications such as face intelligence analysis, face analysis information structure pointer can be used as callback function parameter, the letterNumber outputs face recognition results; Foo classes can be face analysis related classes, OutputCallback may be called in one of these face analysis threads, and OutputCallback callback output can be called to the user providing func_callback.

Note: std::function provided by C++11 can replace function pointer in C language as callback function, the former is C++ programming style, the latter is C programming style.

C/C++ callback mechanism is widely used in server-side concurrent programming and games. Cocos2dx, a well-known 2d game framework, uses callback mechanism extensively. Common callback macros are provided as follows. More callback mechanisms can refer to Cocos2dx open source code.

// Cocos2dx new callbacks based on C++11
//
// _u selector_u: Callback function pointer
// _u target_u: Callback object pointer
// ##u VA_ARGS_u: List of variable parameters 
// Std::placeholders:::_1:Indefinite parameter 1, called with parameters passed in from the calling function
// Std::placeholders:::_2:Indefinite parameter 2, called with parameters passed in from the calling function
// Std::placeholders:::_3:Indefinite parameter 3, called with parameters passed in from the calling function
#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__)

std::function/std::bind and some thoughts on abstract factory and factory method

TODO...

Topics: PHP Lambda Programming C