C++ Lambda Basics
Lambdas (C++11+) are first-class anonymous function objects with a compact syntax: `[capture](params) { body }`. This snippet covers the basic form, the difference between by-value `[=]` and by-reference `[&]` captures, and using lambdas with standard algorithms like `std::sort` and `std::for_each`. Reach for them anywhere you would write a small functor or pass a callback.
213 views
3
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
int main() {
auto add = [](int a, int b) { return a + b; };
std::cout << "3+4=" << add(3, 4) << "\n";
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
int sum = std::accumulate(v.begin(), v.end(), 0,
[](int acc, int x) { return acc + x; });
std::cout << "sum=" << sum << "\n";
return 0;
}The square brackets are the capture clause; the parentheses are the parameter list; the braces are the body. The compiler synthesises a closure type with operator(), so the lambda is callable like any function object. auto add = [](int, int) { ... }; stores it in a variable; passing it inline to algorithms is more common. The return type is deduced; you can specify it explicitly with -> int after the parameter list when deduction would be ambiguous.
#include <iostream>
void demoCaptures() {
int multiplier = 10;
// [=] captures everything used in the body BY VALUE (snapshot).
auto byValue = [=](int x) { return x * multiplier; };
multiplier = 1; // does NOT change byValue's snapshot
std::cout << "by value 5*10=" << byValue(5) << "\n";
// [&] captures BY REFERENCE; reads the current outer value each call.
multiplier = 10;
auto byRef = [&](int x) { return x * multiplier; };
multiplier = 100; // affects byRef
std::cout << "by ref 5*100=" << byRef(5) << "\n";
// Mixed: capture multiplier by value, everything else by reference.
int counter = 0;
auto mixed = [=, &counter](int x) { counter++; return x + multiplier; };
mixed(0); mixed(0);
std::cout << "counter=" << counter << "\n";
}
int main() {
demoCaptures();
return 0;
}[=] snapshots every variable used in the body at lambda creation time; the lambda is independent of subsequent changes to the outer variables. [&] does the opposite: every used name is bound by reference, so the lambda sees the current value at call time. Pin captures down explicitly ([multiplier] or [&counter]) for non-trivial lambdas; the catch-all forms make it easy to accidentally extend the lifetime of a stack reference past the lambda's first call. Always prefer named captures over [=] or [&] in code reviewed by humans.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
void demoSort() {
std::vector<std::string> words = {"alpha", "bravo", "charlie", "delta"};
std::sort(words.begin(), words.end(),
[](const std::string& a, const std::string& b) {
return a.size() < b.size();
});
for (const auto& w : words) std::cout << w << " ";
std::cout << "\n";
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
auto evenCount = std::count_if(nums.begin(), nums.end(),
[](int x) { return x % 2 == 0; });
std::cout << "even count=" << evenCount << "\n";
}
int main() {
demoSort();
return 0;
}Standard algorithms accept any callable as a predicate or comparator, and lambdas are the cleanest way to supply one. The comparator for std::sort is bool less(const T& a, const T& b): return true if a should come before b. Predicates for std::count_if, std::any_of, std::find_if follow the same shape with one argument. Pre-C++11 you had to write a free function or a struct with operator(); with lambdas, the predicate sits exactly where it is used, which makes the algorithm call read like a sentence.
