Lambdas
No-Capture Lambdas
I assume that you have experience with lambdas from C#, so what we will do here is cover the syntax that C++ has adopted. All code snippets are from the same file in the same sample.
Sample: LambdaSample\LambdaSample.cpp
// Create a lambda-expression closure.
auto lm1 = []()
{
wcout << L"No capture, parameterless lambda." << endl;
};
// Invoke the lambda.
lm1();
Lambdas with Parameters
// Create a lambda closure with parameters.
auto lm2 = [](int a, int b)
{
wcout << a << L" + " << b << " = " << (a + b) << endl;
};
lm2(3,4);
Specifying a Lambda’s Return Type
The trailing return type here is -> int after the parameter specification.
// Create a lambda closure with a trailing return type.
auto lm3 = [](int a, int b) -> int
{
wcout << a << L" % " << b << " = ";
return a % b;
};
wcout << lm3(7, 5) << endl;
Capturing Outside Variables
int a = 5;
int b = 6;
// Capture by copy all variables that are currently in the scope.
// Note also that we do not need to capture the closure;
// here we simply invoke the anonymous lambda with the
// () after the closing brace.
[=]()
{
wcout << a << L" + " << b << " = " << (a + b) << endl;
//// It's illegal to modify a here because we have
//// captured by value and have not specified that
//// this lambda should be treated as mutable.
//a = 10;
}();
[=]() mutable -> void
{
wcout << a << L" + " << b << " = " << (a + b) << endl;
// By marking this lambda as mutable, we can now modify a.
// Since we are capturing by value, the modifications
// will not propagate outside.
a = 10;
}();
wcout << L"The value of a is " << a << L"." << endl;
[&]()
{
wcout << a << L" + " << b << " = " << (a + b) << endl;
// By capturing by reference, we now do not need
// to mark this as mutable.
// Because it is a reference, though, changes now
// propagate out.
a = 10;
}();
wcout << L"The value of a is " << a << L"." << endl;
// Here we specify explicitly that we are capturing a by
// value and b as a reference.
[a,&b]()
{
b = 12;
wcout << a << L" + " << b << " = " << (a + b) << endl;
}();
// Here we specify explicitly that we are capturing b as
// a reference and that all other captures should be by
// value.
[=,&b]()
{
b = 15;
wcout << a << L" + " << b << " = " << (a + b) << endl;
}();
// Here we specify explicitly that we are capturing a by
// value and that all other captures should be by reference.
[&,a]()
{
b = 18;
wcout << a << L" + " << b << " = " << (a + b) << endl;
}();
Lambdas in Class-Member Functions
When you use a lambda in a class-member function, you cannot use a default capture by reference. This is because the lambda will be provided with a this pointer, and it must be copied. Also, when dealing with reference-counted smart pointers, it’s common to run into problems with the lambda holding a reference to the class. Usually you will never get back to a reference count of zero, causing a memory leak in your program.
Conclusion
If you're familiar with lambda expressions in C#, then you shouldn't have a hard time getting used to the syntax in C++. In the next article, we take a look at the C++ Standard Library.
This lesson represents a chapter from C++ Succinctly, a free eBook from the team at Syncfusion.
Comments