Lambdas and std::function
2 min read
Lambdas and std::function
Lambdas are anonymous functions defined inline. They are especially useful when you need to pass behavior as an argument — to a sorting function, an algorithm, or a callback.
Basic lambda syntax
#include <iostream>
int main() {
auto square = [](int x) { return x * x; };
std::cout << square(5) << "\n"; // 25
std::cout << square(9) << "\n"; // 81
}
The parts: [] is the capture clause (covered next), (int x) is the parameter list, and { return x * x; } is the body. The return type is deduced automatically.
Lambdas with algorithms
The most common use of lambdas is with standard library algorithms:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {5, 2, 8, 1, 9, 3};
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
for (int n : v) std::cout << n << " "; // 9 8 5 3 2 1
std::cout << "\n";
}
Capture clause
A lambda can capture variables from the enclosing scope:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int threshold = 5;
std::vector<int> v = {1, 3, 7, 2, 9, 4, 6};
// Capture threshold by value
auto above = std::count_if(v.begin(), v.end(),
[threshold](int x) { return x > threshold; });
std::cout << above << " values above " << threshold << "\n"; // 3
}
Capture modes:
| Syntax | Meaning |
|---|---|
[x] |
Capture x by value (copy) |
[&x] |
Capture x by reference |
[=] |
Capture all used variables by value |
[&] |
Capture all used variables by reference |
[=, &x] |
Capture all by value, but x by reference |
Capture by reference is efficient but dangerous if the lambda outlives the captured variable.
Mutable lambdas
By default, a by-value capture is const inside the lambda. Use mutable to modify it:
int count = 0;
auto increment = [count]() mutable {
count++;
return count;
};
std::cout << increment() << "\n"; // 1
std::cout << increment() << "\n"; // 2
std::cout << count << "\n"; // 0 — the original is unchanged
std::function
std::function<R(Args...)> is a type-erased wrapper that can hold any callable — a lambda, a free function, a member function, or a functor — with a compatible signature:
#include <functional>
#include <iostream>
void apply(int x, std::function<int(int)> fn) {
std::cout << fn(x) << "\n";
}
int double_it(int x) { return x * 2; }
int main() {
apply(5, double_it); // 10
apply(5, [](int x) { return x * x; }); // 25
std::function<int(int)> fn = [](int x) { return x + 1; };
apply(5, fn); // 6
}
std::function has overhead from type erasure. When performance matters and you only need one concrete type, use a template parameter instead:
template <typename F>
void apply(int x, F fn) {
std::cout << fn(x) << "\n";
}
Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.
View book →