Discussion on C++11 newly introduced lambda expression

  • 2020-05-27 06:39:13
  • OfStack

The first big highlight of the ISO C++ 11 standard is the introduction of Lambda expressions. The basic grammar is as follows:

[capture list] (parameter list) ->return type { function body }

I'm going to talk a little bit about what the parts do

1.[capture list] captures the list into the body of the function so that the body can be accessed
2.(parameter list) parameter list, which is used to represent the parameter list of lambda expressions
3.- > The return value of the return type function {function body} is the body of the function

The lambda expression can be understood as an anonymous function (but it is not). If you want to declare a function using the lambda expression, you need to "name" it.

The lambda expression can represent a closure because it is the class itself
A closure is a block of code that can contain free variables (not bound to a specific object: for example, a chestnut std::function can generate an object, or a pointer to a function that does not point to any function)

Closures are more colloquially described as follows

1. Context-aware functions. Closures can store the context needed by the runtime, so that closures can be used when the context does not exist (the variable a is destroyed, but can be used in closures)
2. Think of a closure as a class that overloads operator(), with the meaning of state interpreted as using member variables through the this pointer
3.capture list is how lambda expressions implement closures

Simple use example


C++11 provides a new feature for auto, which, like its name 1, can now be viewed as auto-adapted to most types
Use auto to replace the type of the variable, provided it is initialized by an explicitly typed initializer, using the auto keyword

 auto f = [](){}; 
 auto f = [](int a, int b)->int {return a + b; };
 f(1, 2);// You need to use it this way 

This lambda expression can be used for any function type

 typedef int(*FUNC)(int a, int b);
 int main()
   FUNC a= [](int a, int b) {return a + b; };
   printf("%d\n", a(1, 2));

Any method that declares a function can receive an lambda expression without a capture list

 typedef std::function<int(int a, int b)> FUNC;
 int main()
   FUNC a= [](int a, int b) {return a + b; };
   printf("%d\n", a(1, 2));


The use of capture list in the lambda expression

 int func(int a, int b, std::function<int(int, int)> f)
   return f(a, b);
 int a=1 ; 
 int b=2;
 int c=3;
 int d = func(a, b, [a, &b](int m, int n) {
     printf("a = %d\n", a); // a Is captured by passing a value, mutable It only works in the body of the function 
     printf("b = %d\n", b); // b Is a reference pass capture, mutable It can be external b The impact 
                //printf("c = %d\n", c); // c inaccessible 
     return m + n;
 typedef int(*FUNC)(int m, int n,std::function<int(int ,int )> f);
 void test()
   FUNC oho;
   int a = 10;
   int b = 20;
   auto func = [&a, &b](int m, int n) {printf("a:%d b:%d\n", a, b); return m + n; };

1. [] empty. No function object arguments are used.
2. (=). All visible local variables within the scope of Lambda (including this of Lambda's class) can be used inside the function body and are passed by value (equivalent to the compiler automatically passing all local variables by value for us).
3.[ & ]. The body of the function can use all visible local variables within the scope of Lambda (including this of the class Lambda is in) and pass by reference (the compiler automatically passes all local variables by reference for us).
4. [this]. The member variables of the class in which Lambda resides can be used inside the function body.
5. [a]. Pass a by value. When passing by value, the function body cannot modify the copy of a passed in, because the function is const by default. To modify the copy of a passed in, you can add the mutable modifier.
6.[ & a]. Pass a by reference.
7.[a, & b]. Pass a by value and b by reference.
8. [=, & a, & b]. Except for a and b, which are passed by reference, all parameters are passed by value. Note that the position of the = sign must be in the first 1
9.[ & , a b]. All parameters are passed by reference, except for a and b, which are passed by value. & The symbol must be in the first position

Add mutable when you want to change the variables captured by the pass-through method

[a, &b, &b2](int m, int n)mutable {a *= 2; return m*n; }:


Other USES of lambda expressions

 class A
   void test()
     auto f = [this](int m, int n) {printf("%d\n", a); };
   int a;

The lambda expression is essentially a closure type, although it can be assigned to a function pointer, but only if the capture list is empty. When the capture list has a value, auto should be used to receive the lambda expression, or std::function is also acceptable

main::__l2:: < lambda_eb7b0a89c14bee3d2620c108ffb635c6 >
// this is the type of an lambda expression that is displayed in VS2015. What will auto use to receive the call?

Essentially, no assignment is allowed between lambda expressions

 auto a = [](int m, int n) {return m + n; };
 auto b = [](int m, int n) {return m - n; };
 a = b;

The operation is illegal because the closure type does not allow the assignment operator, but function Pointers do, that is, the following operations can be performed

 typedef int(*FUNC)(int a, int b);
 int main()
   FUNC a = [](int a, int b) {return a + b; };
   FUNC b = [](int a, int b) {return a + b; };
   a = b;
   return 0;

std::function can also be assigned, and he can do it with the lambda expression of capture list

 typedef std::function<int(int,int)> FUNC;
 int m = 10;
 int n = 20;
 FUNC a = [m, n](int a, int b){printf("%d\n", m); return a + b; };
 FUNC b = [m, n](int a, int b){return a + b; };
 b = a;
 b(1, 2);
 // The result of the execution is ok m printout 

That's the end of c++11's new lambda expression, which I hope you enjoy

Related articles: