Detailed explanation of Lambda expression in C++

Lambda expression

Lambda expression format

Lambda expressions in C++ 11 are used to define and create anonymous function objects to simplify programming.

The syntax of Lambda is as follows:

[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}  

 

Code format:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
using fptr = int(*)(int& obj);  
  
int main()  
{  
    fptr fobj = [](int& obj)mutable throw(int)->int {return obj; };  
}  

 

As you can see, Lambda is mainly divided into five parts: [function object parameter], (operator overload function parameter), mutable or exception declaration, -> return value type, {function body}.

Capture list: [capture parameter list]

Identifies the beginning of a Lambda expression. This part must exist and cannot be omitted. Function object parameters are passed to the constructor of the function object class automatically generated by the compiler. Function object parameters can only use those local variables that are visible in the scope of the Lambda until the Lambda is defined (including this of the class where the Lambda is located). Function object parameters have the following forms:

 

① Empty: do not capture any external parameters. The capture is actually "the variable in the scope is used directly in the function body";

② =: The function body can use all visible local variables in the scope of Lambda (including this of the class where Lambda is located), and it is a value transfer method (equivalent to the compiler automatically passing all local variables by value for us);

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [=](int& obj)mutable {obj += a; cout << obj << endl; });  
}  

 

 

Pass a variable by value:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [a](int& obj)mutable {obj += a; cout << obj << endl; });  
}  

 

 

Note:

The function of Mutable is to modify the value of the variable captured by the capture list inside the lambda function body, but since I pass in the parameters by value transfer, changing a inside the lambda function body will not cause the external a to change.

③ &: The function body can use all visible local variables within the scope of Lambda (including this of the class where Lambda is located), and it is passed by reference (equivalent to the compiler automatically passing all local variables by reference for us);

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [&](int& obj)mutable {obj += a; cout << obj << endl; });  
} 

 

 

To capture a single variable by reference:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
  
int main()  
{  
    int a = 10;  
    vector<int> obj{ 1,2,3,4,5 };  
    for_each(obj.begin(), obj.end(), [&a](int& obj)mutable {obj += a; cout << obj << endl; });  
} 

 

 

④ this: The member variable in the class where Lambda is located can be used in the function body;

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    void ShowInf()  
    {  
        function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };  
        fptr(); // 调用lambda函数  
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
} 

 

note:

⑴ The prototype of the lambda expression here is function<return data type (parameter data type)>, which is similar to the function pointer in the C language. In fact, the two are essentially the same, but the lambda expression has more "captures" List" only;

⑵ Remember: because we pass in this pointer, static members cannot be called in the class!

Is the following code correct:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
    static int mark;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    function<void()> ShowInf()  
    {  
         return [this]() {cout << this->name << "的年龄为" << this->age << endl; };  // 返回lambda表达式
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
}  

 

This is wrong. Let us explore why it is wrong?

The data type returned by the lambda expression in the above code is void, so the result of the return lambda expression is also void.

New usage of Lambda function:

#include <iostream>  
using namespace std;  
#include <algorithm>  
#include <vector>  
#include <string>  
#include <functional>  
  
class Person  
{  
public:  
    int age;  
    string name;  
    static int mark;  
public:  
    Person(int age, string name)  
    {  
        this->age = age;  
        this->name = name;  
    }  
    void ShowInf()  
    {  
        function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };  
        fptr(); // 调用lambda函数  
    }  
};  
  
int main()  
{  
    Person obj(12, "张三");  
    obj.ShowInf();  
    int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型  
    cout << typeid(fptr1).name() << endl;  
}  

 

Take a look at the above code, the following code is the most significant:

int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型   

 

fptr is an int type, why is this?

function<int(int)> fptr1 = [&](int obj) {cout << obj << endl; return 0; };  
fptr1(4);  

 

The equivalent code is shown above, in fact, the last parenthesis of the lambda expression is used to pass in parameters.

But there is a prerequisite for this. The data type returned by the lambda expression cannot be void. For the void data type, this form is not available, that is, there is no variable to receive void type data.

The form of a lambda expression whose return value data type is void is as follows:

[&](int obj) {cout << obj << endl; }(9);  

 

⑤ a, &b: Pass a by value and b by reference;

⑥ =, &a, &b. Except a and b are passed by reference, other parameters are passed by value;

⑦ &, a, b. Except for a and b which are passed by value, other parameters are passed by reference.

Variables that do not need to declare data types can be defined in the capture list and used in the body of the lambda function:

 

Parameter list: (function parameter list)

Identifies the parameter of the overloaded () operator. If there is no parameter, this part can be omitted. Parameters can be passed by value (such as: (a, b)) and by reference (such as: (&a, &b)).

mutable or exception statement

This part can be omitted. When passing function object parameters by value, after adding the mutable modifier, the passed copy can be modified (note that the copy can be modified, not the value itself). The exception declaration is used to specify the exception thrown by the function, such as throwing an integer type exception, you can use throw(int).

-> Return value type

Identifies the type of the return value of the function. When the return value is void, or there is only one return in the function body (the compiler can automatically infer the return value type at this time), this part can be omitted.

{Function body}

Identifies the realization of the function. This part cannot be omitted, but the function body can be empty.

Instantiate anonymous functions

Store anonymous functions in variables, arrays, or vectors and pass them as named parameters:

#include <iostream>  
using namespace std;  
#include <functional>  
#include <vector>  
  
int main()  
{  
    function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; }; // 必须参数类型一一对应  
    fptr(1, 1);  
    vector<function<void(int, int)>> obj{ fptr };  
    obj[0](1, 2);  
    function<void(int, int)> fptr_array[1]{ fptr };  
    fptr_array[0](4, 6);  
}  

 

Lambda anonymous function and function pointer mutual conversion

#include <iostream>  
using namespace std;  
#include <functional>  
  
using f_ptr = void(*)(int, int);  
  
int main()  
{  
    function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };  
    f_ptr fptr1 = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };  
    //f_ptr = fptr; // 不存在function<void(int,int)>对象转化至void(*)(int, int)对象  
    fptr1(1, 3);  
} 

 

Note: Since lambda expressions are more advanced than function pointers, that is, there is an additional function of "capturing external data". Therefore, when we assign lambda expressions to function pointers of the corresponding type, the capture list [] must be air!

Guess you like

Origin blog.csdn.net/weixin_45590473/article/details/111396362