Lambda_expressions
Lambda Expressions
Section titled “Lambda Expressions”Lambdas provide a way to define anonymous function objects inline. They’re extremely useful with STL algorithms and as callbacks.
Lambda Syntax
Section titled “Lambda Syntax”[ captures ] ( parameters ) -> return_type { body }- captures: Variables from surrounding scope
- parameters: Function parameters (can be empty)
- return_type: Return type (often auto-deduced)
- body: Function body
Basic Lambdas
Section titled “Basic Lambdas”// No parameters, no capturesauto hello = []() { std::cout << "Hello!\n"; };hello(); // "Hello!"
// With parametersauto add = [](int a, int b) { return a + b; };int result = add(5, 3); // 8
// With return typeauto divide = [](double a, double b) -> double { return a / b;};Captures
Section titled “Captures”Captures allow lambdas to access variables from the surrounding scope:
Capture by Value
Section titled “Capture by Value”int x = 10;auto lambda = [x]() { return x; }; // Copies xCapture by Reference
Section titled “Capture by Reference”int x = 10;auto lambda = [&x]() { x = 20; }; // References xCapture All
Section titled “Capture All”int a = 1, b = 2;
// Capture all by valueauto f1 = [=]() { return a + b; };
// Capture all by referenceauto f2 = [&]() { return a + b; };
// Mixed: a by value, b by referenceauto f3 = [a, &b]() { b = 20; return a; };Mutable Lambdas
Section titled “Mutable Lambdas”int count = 0;
auto counter = [count]() mutable { count++; // Can modify captured copy return count;};
counter(); // 1counter(); // 2 (count is now 2)Generic Lambdas (C++14)
Section titled “Generic Lambdas (C++14)”auto add = [](auto a, auto b) { return a + b; };
int i = add(1, 2); // 3double d = add(1.5, 2.5); // 4.0std::string s = add("Hello, ", "World!"); // "Hello, World!"Lambda with STL Algorithms
Section titled “Lambda with STL Algorithms”#include <algorithm>#include <vector>
std::vector<int> vec = {5, 2, 8, 1, 9, 3};
// Find first element > 5auto it = std::find_if(vec.begin(), vec.end(), [](int n) { return n > 5; });
// Sort with custom comparatorstd::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });
// Count elementsint count = std::count_if(vec.begin(), vec.end(), [](int n) { return n % 2 == 0; });
// Transformstd::vector<int> result;std::transform(vec.begin(), vec.end(), std::back_inserter(result), [](int n) { return n * 2; });Lambda as Comparator
Section titled “Lambda as Comparator”std::set<int, std::function<bool(int, int)>> customSet( [](int a, int b) { return a > b; } // Descending order);Lambda as Callback
Section titled “Lambda as Callback”void processData(int value, std::function<void(int)> callback) { // Process... callback(value * 2);}
int main() { processData(5, [](int result) { std::cout << "Result: " << result << "\n"; });}Complete Example: Event System
Section titled “Complete Example: Event System”#include <iostream>#include <vector>#include <functional>
class EventManager {private: std::vector<std::function<void()>> listeners;
public: void subscribe(std::function<void()> callback) { listeners.push_back(callback); }
void trigger() { for (auto& listener : listeners) { listener(); } }};
int main() { EventManager events; int notificationCount = 0;
// Subscribe with lambda (captures notificationCount by reference) events.subscribe([¬ificationCount]() { notificationCount++; std::cout << "Event triggered!\n"; });
events.subscribe([¬ificationCount]() { std::cout << "Second listener. Total: " << notificationCount << "\n"; });
std::cout << "=== Trigger 1 ===\n"; events.trigger();
std::cout << "=== Trigger 2 ===\n"; events.trigger();
return 0;}Lambda vs std::function
Section titled “Lambda vs std::function”- Lambda: Anonymous function object, lightweight
- std::function: Type-erased wrapper, can store any callable
// Lambda (direct type)auto lambda = [](int x) { return x * 2; };
// std::function (type-erased)std::function<int(int)> func = lambda;Best Practices
Section titled “Best Practices”- Use captures wisely - prefer
const&for read-only
for (const auto& item : items) { process([&item]() { /* use item */ });}- Avoid unnecessary captures - only capture what’s needed
// Goodauto f = [value]() { return value * 2; };
// Avoid (unnecessary capture)int unused = 0;auto f = [unused, value]() { return value * 2; };- Use generic lambdas (C++14) for flexible code
Key Takeaways
Section titled “Key Takeaways”- Lambdas create anonymous function objects inline
- Captures access variables from surrounding scope
- Use
[=]for copy,[&]for reference - Lambdas work great with STL algorithms
- Generic lambdas (C++14) work with any type
Next Steps
Section titled “Next Steps”Let’s learn about move semantics - a powerful feature that enables efficient resource transfer.
Next Chapter: 26_move_semantics.md - Move Semantics and Rvalue References