The essence and application of lambda expression

table of Contents

Lambda expression

Basic structure of lambda expression

The essence of lambda expression

Analyze the meaning of each part of the lambda expression

Capture list []

Form attendance table ()

mutable statement

Exception handling  

-> Specify the function return value type

Function body {}

Special note: the function handle returned by the lambda function

Lambda function implements unary predicate

Lambda function implements binary predicate

Use Lambda function in transform function


Lambda expression

Basic structure of lambda expression

 

The essence of lambda expression

Lambda expressions are anonymous classes (or structures) that implement operator( ).

Analyze the meaning of each part of the lambda expression

Capture list []

The meaning and format of the capture list

The capture 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:

air

Without any function object parameters

=

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 a value transfer method (equivalent to the compiler automatically passing all local variables by value for us)

&

 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

this

The function body can use the member variables in the class of Lambda

a

Pass a by value. When passing by value, the copy of a passed in cannot be modified in the function body, because the function is const by default. To modify the passed copy, you can add a mutable modifier

&a

Pass a by reference

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 a and b are passed by value, other parameters are passed by reference

Code example

// lambda表达式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。  
//  
  
#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional>  
using namespace std;  
  
struct Student  
{  
    string name;  
    float mark;  
      
    Student(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
  
    std::function<float(float)> LambdaExpression = [this](float AddMark)->float {return mark + AddMark; }; // 这里传入的是结构体的指针,故lambda函数体内可以使用 Lambda 所在类中的成员变量
};  
  
int main()  
{  
    Student stud1("666", 98.8);  
    float FinalMark = stud1.LambdaExpression(1);  
}  

 

In fact, the meaning of the capture list is just like its name, "capture all the values ​​that can be used in the scope". Let's see: when we declare a Student instance, we call the member function LambdaExpression , we see that this function not only obtains the actual parameter AddMark we passed in to him, but also obtains the class member variables. This is the purpose of the capture list, it can use the value of the variable in the scope and outside the function. The variables in the lambda function have two sources: the capture list and the function parameter list. The latter requires us to pass in the actual parameters to obtain, and the former needs to be obtained within the scope of the lambda function (outside the lambda function).

Form attendance table ()

The meaning and format of the formal parameter list

The format and meaning of the formal parameter list is the same as that of a normal function, and we need to pass in the formal parameters when using the function.

mutable statement

mutable meaning

Identifier

effect

mutable

When we declare the mutable identifier after the formal parameter list, we can change the variables captured in the capture list in the function body. By default, the lambda function is always a const function, and mutable can cancel its constancy. When using this modifier, the parameter list cannot be omitted.

Code example

// lambda表达式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。  
//  
  
#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional>  
using namespace std;  
  
struct Student  
{  
    string name;  
    float mark;  
      
    Student(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
  
    std::function<float(float)> LambdaExpression = [this](float AddMark)mutable->float {return ++mark + AddMark; }; // 改变了表达式内捕获变量的值  
};  
  
int main()  
{  
    Student stud1("666", 98.8);  
    float FinalMark = stud1.LambdaExpression(1);  
}  

 

Note: Here I am talking about "change the value of the captured variable in the expression", which means that "the value of the captured variable outside the expression is not changed", this is because our capture list uses "value transfer ( [ this ] )”, if you change to the following code, you can fundamentally change the value of the captured variable itself:

// lambda表达式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。  
//  
  
#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional>  
using namespace std;  
  
struct Student  
{  
    string name;  
    float mark;  
      
    Student(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
  
    std::function<float(float)> LambdaExpression = [&](float AddMark)mutable->float {return ++mark + AddMark; }; // 改变了捕获变量的值  
};  
  
int main()  
{  
    Student stud1("666", 98.8);  
    float FinalMark = stud1.LambdaExpression(1);  
    cout << stud1.mark << endl; // 99.8 = 98.8 + 1  
}  

 

Exception handling  

There are some classes in the cpp standard library that represent exceptions, these classes are derived from the exception class

The header file "#include<exception>" is required:

 

abnormal

description

std::exception

This exception is the parent class of all standard C++ exceptions.

std::bad_alloc

The exception can be thrown by new .  

std::bad_cast

The exception can be thrown through dynamic_cast .  

std::bad_exception

This is very useful when dealing with unexpected exceptions in C++ programs.

std::bad_typeid

The exception can be thrown by typeid .  

std::logic_error

In theory, an anomaly can be detected by reading the code.

std::domain_error

When an invalid mathematical field is used, this exception will be thrown.

std::invalid_argument

This exception will be thrown when invalid parameters are used.

std::length_error

This exception will be thrown when a std::string that is too long is created .

std::out_of_range

This exception can be thrown by methods such as std::vector and std::bitset<>::operator[]() .

std::runtime_error

Anomalies that cannot theoretically be detected by reading the code.

std::overflow_error

When a mathematical overflow occurs, this exception is thrown.

std::range_error

This exception is thrown when trying to store a value out of range.

std::underflow_error

This exception will be thrown when a mathematical underflow occurs.

 

Code example

 

You can use the try-catch structure in the body of the lambda for exception handling, and call the contents of the exception handling library in it. The following shows the combined use of try-catch structure and exception library:

// bad_function_call example  
#include <iostream>     // std::cout  
#include <functional>   // std::function, std::plus, std::bad_function_call  
int main () {  
  std::function<int(int,int)> foo = std::plus<int>();  
  std::function<int(int,int)> bar;  
  
  try {  
    std::cout << foo(10,20) << '\n';  
    std::cout << bar(10,20) << '\n';  
  }  
  catch (std::bad_function_call& e)  
  {  
    std::cout << "ERROR: Bad function call\n";  
  }  
  
  return 0;  
}  

 

-> Specify the function return value type

->Use of identifiers

When you do not specify the return value type, the lambda expression will automatically determine the return type of the expression based on the type of the value returned by return. But if we use "->" to specify the value type returned by the lambda expression, then the return value type of the expression will not change depending on the data type returned by return.

Code example

// lambda表达式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。  
//  
  
#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional>  
using namespace std;  
  
struct Student  
{  
    string name;  
    float mark;  
      
    Student(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
  
    std::function<float(float)> LambdaExpression = [&](float AddMark)mutable->float {return ++mark + AddMark; }; // 改变了捕获变量的值  
};  
  
int main()  
{  
    Student stud1("666", 98.8);  
    float FinalMark = stud1.LambdaExpression(1);  
    cout << stud1.mark << endl; // 99.8 = 98.8 + 1  
}  
// 可以在lambda函数体内包含像这样的try-catch结构进行异常处理

 

Function body {}

Like different functions, lambda functions can also have function bodies that span multiple lines, but usually lambda functions are used to avoid declaring some short and simple function bodies. Don't use very long lambda expressions (including multiple statements), but use function objects instead, because every time you use a lambda expression, you need to redefine it, which does not help improve the reusability of the code.

Special note: the function handle returned by the lambda function

The function handle format is as follows

 

Format analysis

In Function<float(float)>, the first float is the return type of the function, and the second float is the type passed in by the formal parameter. Which LambdaExpression is a function handle, so we have the following call format:

float FinalMark = stud1.LambdaExpression(1); 

   

Lambda function implements unary predicate

#include <functional>  
#include <iostream>  
#include <algorithm>  
#include <vector>  
using namespace std;  
  
int main()  
{  
    vector<int> VectorArray{ 6,3,1,4,7,5,3,2 };  
    int divisor = 2;  
    vector<int>::iterator itor = find_if(VectorArray.begin(), VectorArray.end(), [&divisor](int Element) {return Element % divisor == 0; });  
    cout << *itor << endl; // 第一个偶数元素为6  
}  

 

Lambda function implements binary predicate

#include <vector>  
#include <algorithm>  
#include <iostream>  
using namespace std;  
  
int main()  
{  
    vector<int> VectorArray{ 2,1,5,4,9,6,7 };  
    sort(VectorArray.begin(), VectorArray.end(), [](const int& var1, const int& var2)->bool {return var1 > var2; });  
    for_each(VectorArray.begin(), VectorArray.end(), [](const int& var) {cout << var << " "; });  
}  

 

Use Lambda function in transform function

#include <iostream>  
#include <algorithm>  
#include <vector>  
using namespace std;  
  
int main()  
{  
    vector<int> VectorArray1{ 1,10,5,2,8,4 }, VectorArray2{ 6,3,8,3,0,2 }, VectorArray3(VectorArray2.size());  
    // 在把数据装入VectorArray3之前,一定要预留充足的空间,否则会报错  
    transform(VectorArray1.begin(), VectorArray1.end(), VectorArray2.begin(), VectorArray3.begin(), [](const int& var1, const int& var2)->int {return var1 * var2; });  // 将两个动态数组内的元素相乘
    for_each(VectorArray3.begin(), VectorArray3.end(), [](int& var) {cout << var << " "; });  // 输出每个元素
}  

 

Guess you like

Origin blog.csdn.net/weixin_45590473/article/details/107986837
Recommended