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