In our previous Lambda expression examples, we keep the capturing part and the square bracket ([]) empty since the Lambda doesn't capture anything and doesn't have any extra member variable in the anonymous object generated by the compiler. We can also specify the object we want to capture in the Lambda expression by specifying it in this square bracket. Let's take a look at the following piece of code to go through the discussion:
/* lambda_capturing_by_value.cpp */
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
auto main() -> int
{
cout << "[lambda_capturing_by_value.cpp]" << endl;
// Initializing a vector containing integer element
vector<int> vect;
for (int i = 0; i < 10; ++i)
vect.push_back(i);
// Displaying the elements of vect
cout << "Original Data:" << endl;
for_each(
begin(vect),
end(vect),
[](int n){
cout << n << " ";
});
cout << endl;
// Initializing two variables
int a = 2;
int b = 8;
// Capturing value explicitly from the two variables
cout << "Printing elements between " << a;
cout << " and " << b << " explicitly [a,b]:" << endl;
for_each(
begin(vect),
end(vect),
[a,b](int n){
if (n >= a && n <= b)
cout << n << " ";
});
cout << endl;
// Modifying variable a and b
a = 3;
b = 7;
// Capturing value implicitly from the two variables
cout << "printing elements between " << a;
cout << " and " << b << " implicitly[=]:" << endl;
for_each(
begin(vect),
end(vect),
[=](int n){
if (n >= a && n <= b)
cout << n << " ";
});
cout << endl;
return 0;
}
In the preceding code, we will try to capture the value in the Lambda expression, explicitly and implicitly. Let's suppose we have two variables, a and b, and we want to explicitly capture the values, we can specify them in the Lambda expression using the [a,b] statement, and then using the values inside the function body. Moreover, if we wish to capture the value implicitly, just use [=] for the capturing part and then the expression will know which variable we intend to use when we specify them in the function body. If we run the preceding code, we will get the following output on the screen:
We can also mutate the state of the values we capture without modifying the value outside the Lambda expression function body. For this purpose, we can use the same techniques as used previously, and add the mutable keyword as shown in the following block of code:
/* lambda_capturing_by_value_mutable.cpp */
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
auto main() -> int
{
cout << "[lambda_capturing_by_value_mutable.cpp]" << endl;
// Initializing a vector containing integer element
vector<int> vect;
for (int i = 0; i < 10; ++i)
vect.push_back(i);
// Displaying the elements of vect
cout << "Original Data:" << endl;
for_each(
begin(vect),
end(vect),
[](int n){
cout << n << " ";
});
cout << endl;
// Initializing two variables
int a = 1;
int b = 1;
// Capturing value from the two variables
// without mutate them
for_each(
begin(vect),
end(vect),
[=](int& x) mutable {
const int old = x;
x *= 2;
a = b;
b = old;
});
// Displaying the elements of vect
cout << "Squared Data:" << endl;
for_each(
begin(vect),
end(vect),
[](int n) {
cout << n << " ";
});
cout << endl << endl;
// Displaying value of variable a and b
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
The preceding code will double the element of the vect vector. It uses capturing by value in the Lambda expression and also the mutable keyword. As we can see, we passed the vector element by reference (int& x) and multiplied it by two, then changed the value of a and b. However, since we use the mutable keyword, the final result of a and b will remain the same, although, we have passed the vector by reference. The output on the console looks like the following screenshot:
If we want to change the value of the a and b variables, we have to use the Lambda expression to capture by reference. We can do this by passing the reference to the angle bracket in the Lambda expression, for instance, [&a, &b]. For more detail, let's take a look at the following piece of code:
/* lambda_capturing_by_reference.cpp */
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
auto main() -> int
{
cout << "[lambda_capturing_by_reference.cpp]" << endl;
// Initializing a vector containing integer element
vector<int> vect;
for (int i = 0; i < 10; ++i)
vect.push_back(i);
// Displaying the elements of vect
cout << "Original Data:" << endl;
for_each(
begin(vect),
end(vect),
[](int n){
cout << n << " ";
});
cout << endl;
// Initializing two variables
int a = 1;
int b = 1;
// Capturing value from the two variables
// and mutate them
for_each(
begin(vect),
end(vect),
[&a, &b](int& x){
const int old = x;
x *= 2;
a = b;
b = old;
});
// Displaying the elements of vect
cout << "Squared Data:" << endl;
for_each(
begin(vect),
end(vect),
[](int n) {
cout << n << " ";
});
cout << endl << endl;
// Displaying value of variable a and b
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
The preceding code has the same behavior with the lambda_capturing_by_value_mutable.cpp file that will double the element of the vect vector. However, by capturing by reference, it now also modifies the value of a and b when they are processed in the for_each loop. The a and b values will be changed at the end of the code, as we can see in the following screenshot: