Lambda Expressions & std::function
ল্যাম্বডা এক্সপ্রেশন
1. The Lambda
A lambda is a function defined inline. C++ generates an anonymous class with operator() for it.
#include <iostream>
int main() {
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << "\n";
// Lambda used in-place
auto sq = [](int x) { return x * x; };
std::cout << sq(5) << "\n";
}
2. Captures
The [ ] at the start says how to capture variables from the enclosing scope:
| Capture | Meaning |
|---|---|
[] | No captures |
[x] | Copy of x |
[&x] | Reference to x |
[=] | Copy everything used (avoid) |
[&] | Reference to everything used (avoid) |
[x, &y] | Mix: copy x, ref to y |
[this] | Capture this pointer in member fn |
#include <iostream>
int main() {
int x = 10;
auto by_value = [x]() { return x; };
auto by_ref = [&x]() { ++x; };
by_ref();
std::cout << by_value() << " " << x << "\n"; // 10 11
}
& dangles. Prefer copy capture for stored lambdas.
3. Generic Lambdas (C++14)
Use auto for parameters → an implicit template:
auto add = [](auto a, auto b) { return a + b; };
add(3, 4); // int
add(1.5, 2.5); // double
add(std::string{"hi"}, " world"); // string
4. std::function — Type-Erased Callable
Holds any callable (function pointer, lambda, functor) with a given signature:
#include <iostream>
#include <functional>
#include <vector>
int main() {
std::vector<std::function<int(int)>> ops;
ops.push_back([](int x) { return x * 2; });
ops.push_back([](int x) { return x + 1; });
ops.push_back([](int x) { return x * x; });
int n = 5;
for (auto& op : ops) std::cout << op(n) << " ";
std::cout << "\n";
}
auto or template parameter.
5. Mutable Lambdas
auto counter = [n = 0]() mutable { return ++n; };
counter(); counter(); counter(); // returns 1, 2, 3
Lambdas are const by default. mutable allows modification of captured-by-value variables.
6. Practice Problems
- Write a lambda that returns the square of its argument.
✨ Show Answer
auto sq = [](int x) { return x * x; }; - Use a lambda with std::sort to sort descending.
✨ Show Answer
std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; }); - Capture
thresholdby value in a count_if predicate.✨ Show Answer
int threshold = 10; int n = std::count_if(v.begin(), v.end(), [threshold](int x){ return x > threshold; }); - What is a closure?
✨ Show Answer
An object that holds (encloses) some captured state plus a function. C++ lambdas with captures generate closure objects.
- Why use
std::function?✨ Show Answer
To store callables of different concrete types in the same variable/container. Pays runtime cost.
- Define a lambda that increments a counter every call.
✨ Show Answer
auto next = [n = 0]() mutable { return ++n; }; - When does capture-by-reference become dangerous?
✨ Show Answer
When the lambda is stored or returned and outlives the referenced variable. The reference dangles.
- Use a lambda inside a class member function. How to access members?
✨ Show Answer
auto f = [this]() { return member_; }; - Generic lambda summing two values.
✨ Show Answer
auto sum = [](auto a, auto b) { return a + b; }; - Lambda with explicit return type.
✨ Show Answer
auto div = [](int a, int b) -> double { return a / (double)b; }; - Why use
autofor storing a lambda instead ofstd::function?✨ Show Answer
No type erasure cost; compiler can inline.
std::functionis for when you need a uniform type at runtime. - A lambda that captures vector by reference and finds max.
✨ Show Answer
std::vector<int> v = {3,1,4}; auto maxer = [&v](){ return *std::max_element(v.begin(), v.end()); }; - Pass a lambda to std::for_each.
✨ Show Answer
std::for_each(v.begin(), v.end(), [](int& x){ x *= 2; }); - What does
operator()have to do with lambdas?✨ Show Answer
The compiler generates an anonymous class with
operator()overloaded to your lambda body. The lambda is an instance of that class. - Use a lambda as a comparator with std::map.
✨ Show Answer
auto cmp = [](int a, int b){ return a > b; }; std::map<int, std::string, decltype(cmp)> m(cmp); - Recursive lambda — possible?
✨ Show Answer
std::function<int(int)> fact = [&](int n) { return n < 2 ? 1 : n * fact(n - 1); };Or use a parameter trick (Y-combinator style).
Summary
Lambdas make functions first-class. Capture rules: prefer explicit captures over [=]/[&].
Use auto to store a lambda when type is local. Use std::function when you need a uniform
callable type at runtime, but be aware of its cost.