table of Contents
Basic structure of lambda expression
The essence of lambda expression
Analyze the meaning of each part of the lambda expression
-> Specify the function return value type
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 << " "; }); // 输出每个元素
}