C++ 11 added STD ::function, STD ::bind, lambda expressions and other encapsulations to make function calls easier.

std::function

So before WE talk about STD :: Function, what are callable objects

A callable object is one of the following:

  • Is a function pointer
  • Is a class object (the fabled functor) with operator() member functions, lambda expressions
  • Is a class object that can be converted to a function pointer
  • A pointer to a class member (function)
  • Bind expression or other function object

STD :: Function is a wrapper for this callable, and can be thought of as a function object representing the abstract concept of a function. An instance of STD ::function can store, copy, and call any callable object. The stored callable object is called the target of STD ::function, or null if STD ::function does not contain a target. The target that calls the empty STD ::function throws the STD ::bad_function_call exception.

Use reference to the following example code:

std::function<void(int)> f; Void #include <functional> #include <iostream> struct Foo {Foo(int num) : num_(num) {} void print_add(int i) const { std::cout << num_ + i << '\n'; } int num_; }; void print_num(int i) { std::cout << i << '\n'; } struct PrintNum { void operator()(int i) const { std::cout << i << '\n'; }}; Int main() {STD ::function<void(int)> f_display = print_num; f_display(-9); // store lambda STD ::function<void()> f_display_42 = []() {print_num(42); }; f_display_42(); STD ::function<void()> f_Display_31337 = STD ::bind(print_num, 31337); f_display_31337(); STD ::function<void(const Foo&, int)> f_add_display = &Foo::print_add; STD ::function<void(const Foo&, int)> f_add_display = &Foo::print_add; const Foo foo(314159); f_add_display(foo, 1); f_add_display(314159, 1); STD ::function<int(Foo const&)> f_num = &foo ::num_; std::cout << "num_: " << f_num(foo) << '\n'; Using STD :: Placeholder ::_1; std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1); f_add_display2(2); // Store calls to member functions and object Pointers STD ::function<void(int)> f_add_display3 = STD ::bind(&Foo::print_add, &Foo, _1); f_add_display3(3); STD ::function<void(int)> f_Display_obj = PrintNum(); f_display_obj(18); }Copy the code

You can see how STD ::function is used above. When STD ::function is populated with appropriate argument lists and return values, it becomes a function wrapper that can accommodate all of these types of calls. STD ::function can also be used as a callback function, or in C++ if you need to use a callback, you must use STD ::function. This is particularly handy, and you can read my previous article on thread pools and timers.

std::bind

With STD :: Bind, callable objects and parameters are bound together, and the result of the binding is saved using STD ::function and deferred until we need to.

STD :: Bind usually does two things:

  • Bind the callable with the argument to another STD ::function for calling
  • So, turn n dollar callable into m(m < n) dollar callable and bind some parameters, using STD :: Placeholder

Specific examples:

#include <functional> #include <iostream> #include <memory> void f(int n1, int n2, int n3, const int& n4, int n5) { std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << std::endl; } int g(int n1) { return n1; } struct Foo { void print_sum(int n1, int n2) { std::cout << n1 + n2 << std::endl; } int data = 10; }; int main() { using namespace std::placeholders; // For _1, _2, _3... // demonstrate parameter reordering and passing by reference int n = 7; / / (_1, _2 from STD: : placeholders, and said that the future will be passed to the parameters of f1) auto f1 = STD: : bind (f, _2, 42, _1, STD: : which (n), n); n = 10; f1(1, 2, 1001); // 1 is bound to _1, 2 is bound to _2, Auto f2 = STD ::bind(f, _3, STD ::bind(g, _3), _3, 4, 5); f2(10, 11, 12); // proceed to f(12, g(12), 12, 4, 5); // bind to the member function pointer Foo Foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); // bind to the data member pointer auto f4 = STD ::bind(&Foo::data, _1); std::cout << f4(foo) << std::endl; // Smart Pointers can also be used to call members of the referenced object STD ::cout << f4(STD ::make_shared<Foo>(Foo)) << STD ::endl; }Copy the code

Lambda expressions

Lambda expressions are arguably one of the most important features referenced in c++11. They define an anonymous function that can capture a range of variables for use inside a function. They generally have the following syntax:

auto func = [capture] (params) opt -> ret { func_body; };Copy the code

Where func is the name that can be used as a lambda expression, as a function, capture is a capture list, params is a parameter list, opt is a function option, ret is a return value type, and func_body is the body of a function.

A complete lambda expression:

auto func1 = [](int a) -> int { return a + 1; };
auto func2 = [](int a) { return a + 2; };
cout << func1(1) << " " << func2(2) << endl;Copy the code

As shown above, many times the return value of a lambda expression is obvious, and c++11 allows omitting the expression’s return value definition.

Lambda expressions allow capturing a range of variables:

  • [] No variables are captured
  • [&] Reference capture, which captures all variables in the external scope and uses them as references in the function body
  • [=] value capture, which captures all variables in the external scope and uses a copy within the function
  • The [=, &a] value captures all variables in the external scope, capturing a variable by reference
  • [a] only a variable is captured
  • [this] captures the this pointer in the current class

Example code for lambda expressions:

int a = 0; auto f1 = [=](){ return a; }; // A cout << f1() << endl; auto f2 = [=]() { return a++; }; // modify external variables captured by value, error auto f3 = [=]() mutable {return a++; };Copy the code

F2 in this code is uncompiled because we have modified the external variables captured by value. In fact, a lambda expression is equivalent to a functor. The functor is a class object that has a const operator() member function. To be mutable is to remove const.

You can also use lambda expressions to customize STL rules, such as custom sort sorting:

struct A {
    int a;
    int b;
};

int main() {
    vector<A> vec;
    std::sort(vec.begin(), vec.end(), [](const A &left, const A &right) { return left.a < right.a; });
}Copy the code

conclusion

STD ::function and STD :: Bind make it more convenient to encapsulate functions in the normal programming process, while lambda expressions take this convenience to the extreme. Anonymous functions can be defined at the required time without defining classes or functions, etc. It is also very convenient to customize STL rules, making the code more concise. More flexible, improve development efficiency.

The resources

Zh.cppreference.com/w/cpp/utili…

Zh.cppreference.com/w/cpp/utili…

Zh.cppreference.com/w/cpp/langu…

Zh.cppreference.com/w/cpp/named…

Blog.csdn.net/m_buddy/art…

Deep c++11: code optimization and engineering applications

Effective Modern C++

For more articles, please pay attention to my V X public master number: program cat, welcome to exchange.