[Strange thing]Description of std::function and std::bind

1. Callable Objects

There are several definitions of callable objects:

  • Is a function pointer, reference C++ Function Pointer and Function Type
  • Is an object of a class with operator() member functions;
  • Class object that can be converted to a function pointer;
  • A pointer to a class member function;

Although callable objects in_C++ all have a relatively uniform form of operation, there are many different ways to define them, which makes it tedious to save or pass callable objects in a uniform way. std::function and std::bind are provided in C++11 to unify the operations of callable objects.

_Different types of calls may have the same form, such as:

// General function
int add(int a, int b){return a+b;} 

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

// Function object class
struct divide{
    int operator()(int denominator, int divisor){
        return denominator/divisor;
    }
};

_Although the three types of callable objects are different, they share a common form of invocation:

int(int ,int)

_std::function can save the above types as follows:

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

2. std::function

  • std::function is a callable object wrapper and a class template that can hold all callable objects except class member function pointers. It can handle functions, function objects, function pointers in a uniform way and allow them to be saved and deferred.
  • Define format: std::function<function type>.
  • std::function can replace function pointer because it can delay function execution, especially for callback functions. It is more flexible and convenient than ordinary function pointers.

3. std::bind

_Consider the std::bind function as a generic function adapter that accepts a callable object and generates a new callable object to "fit" the parameter list of the original object.

_std::bind binds the callable object with its parameters, and the result of the binding can be saved using std::function. Std::bind has two main functions:

  • Bind the callable object and its parameters as a defense function;
  • Bind only some parameters to reduce the parameters passed in by callable objects.

3.1 std::bind bind normal function

double my_divide (double x, double y) {return x/y;}
auto fn_half = std::bind (my_divide,_1,2);  
std::cout << fn_half(10) << '\n';                        // 5
  • The first argument to bind is the function name, which is implicitly converted to a function pointer when an ordinary function takes an argument. So std::bind (my_divide, _1, 2) is equivalent to std::bind (&my_divide, _1, 2);
  • _ 1 stands for a placeholder, in <function>, std::placeholders::\_1;

3.2 std::bind binds a member function

struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
int main() 
{
    Foo foo;
    auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
    f(5); // 100
}
  • When bind binds a class member function, the first parameter represents the pointer to the member function of the object, and the second parameter represents the address of the object.
  • Specified &Foo::print_that must be displayed Sum, because the compiler does not implicitly convert object member functions to function pointers, it must be in Foo::print_ Add &before sum;
  • When using a pointer to an object member function, you must know which object the pointer belongs to, so the second parameter is the object's address &foo;

3.3 Bind a reference parameter

By default, bind's parameters that are not placeholders are copied into the callable object returned by bind. However, similar to lambda, there are times when parameters bound are expected to be passed by reference or when the type of parameter to be bound cannot be copied.

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std::placeholders;
using namespace std;

ostream & print(ostream &os, const string& s, char c)
{
    os << s << c;
    return os;
}

int main()
{
    vector<string> words{"helo", "world", "this", "is", "C++11"};
    ostringstream os;
    char c = ' ';
    for_each(words.begin(), words.end(), 
                   [&os, c](const string & s){os << s << c;} );
    cout << os.str() << endl;

    ostringstream os1;
    // ostream cannot be copied, if you want to pass it to a bind object,
    // Instead of copying it, you must use the ref function provided by the standard library
    for_each(words.begin(), words.end(),
                   bind(print, ref(os1), _1, c));
    cout << os1.str() << endl;
}

4. Pointer to member function

_Use the following examples to familiarize yourself with the definition of pointers to member functions.

#include <iostream>
struct Foo {
    int value;
    void f() { std::cout << "f(" << this->value << ")\n"; }
    void g() { std::cout << "g(" << 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::f);
    apply(&foo1, &foo2, &Foo::g);
}
  • The member function pointer is defined as void (Foo:*fun)(), the call is the passed argument: &Foo::f;
  • Fun is a pointer to a class member function, so the call is to get the member function *fun (foo1->*fun) () by dereferencing;

Added by Nightseer on Sat, 05 Feb 2022 19:46:57 +0200