- Modern C++:Efficient and Scalable Application Development
- Richard Grimes Marius Bancila
- 583字
- 2021-06-10 18:28:10
Introducing lambda expressions
A lambda expression is used to create an anonymous function object at the location where the function object will be used. This makes your code much more readable because you can see what will be executed. On first sight, a lambda expression looks like a function definition in-place as a function parameter:
auto less_than_10 = [](int a) {return a < 10; };
bool b = less_than_10(4);
So that we don't have the complication of a function that uses a predicate, in this code we have assigned a variable to the lambda expression. This is not normally how you would use it, but it makes the description clearer. The square brackets at the beginning of the lambda expression are called the capture list. This expression does not capture variables, so the brackets are empty. You can use variables declared outside of the lambda expression and these have to be captured. The capture list indicates whether all such variables will be captured by a reference (use [&]) or by a value (use [=]). You can also name the variables that will be captured (if there are more than one, use a comma-separated list) and if they are captured by a value, you use just their names. If they are captured by a reference, use a & on their names.
You could make the preceding lambda expression more generic by introducing a variable declared outside of the expression called limit:
int limit = 99;
auto less_than = [limit](int a) {return a < limit; };
If you compare a lambda expression to a global function, the capture list is a bit like identifying the global variables that the global function can access.
After the caption list, you give the parameter list in parentheses. Again, if you compare a lambda to a function, the lambda parameter list is equivalent to the function parameter list. If the lambda expression does not have any parameters, then you can miss out the parentheses altogether.
The body for the lambda is given in a pair of braces. This can contain anything that can be found in a function. The lambda body can declare local variables, and it can even declare static variables, which looks bizarre, but is legal:
auto incr = [] { static int i; return ++i; };
incr();
incr();
cout << incr() << endl; // 3
The return value of the lambda is deduced from the item that is returned. A lambda expression does not have to return a value, in which case the expression will return void:
auto swap = [](int& a, int& b) { int x = a; a = b; b = x; };
int i = 10, j = 20;
cout << i << " " << j << endl;
swap(i, j);
cout << i << " " << j << endl;
The power of lambda expressions is that you can use them in cases when a function object or a predicate is needed:
vector<int> v { 1, 2, 3, 4, 5 };
int less_than_3 = count_if(
v.begin(), v.end(),
[](int a) { return a < 3; });
cout << "There are " << less_than_3 << " items less than 3" << endl;
Here we declare a vector and initialize it with some values. The count_if function is used to count how many items in the container are less than 3. So, the first two parameters are used to give the range of items to check, and the third parameter is a lambda expression that performs the comparison. The count_if function will call this expression for every item in the range that is passed in via the a parameter of the lambda. The count_if function keeps a running count of how many times the lambda returns true.