Expert · Modern C++: lambdas, C++17 and C++20 essentials · topic 30 of 42 · 30 min
Lambdas: small functions written in place
Explanation
Why lambdas?
Algorithms like std::sort, std::count_if and std::find_if need a small piece of logic: how to compare, what to count. Before C++11 you had to write a separate named function or a class for each one, far away from where it was used. A lambda expression lets you write that small function inline, exactly where it is needed.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> marks = {35, 82, 47, 91, 28};
int passMark = 40;
auto passed = std::count_if(marks.begin(), marks.end(),
[passMark](int m) { return m >= passMark; });
std::cout << passed << '\n'; // 3
}The parts of a lambda
[capture](parameters) -> returnType { body }
auto add = [](int a, int b) { return a + b; }; // return type deduced
auto half = [](double x) -> double { return x / 2; }; // explicit return type
std::cout << add(2, 3) << ' ' << half(5) << '\n'; // 5 2.5Captures
| Capture | Meaning |
|---|---|
| [] | captures nothing |
| [x] | copies x into the lambda when the lambda is created |
| [&x] | refers to x; changes and later updates are shared |
| [=] | copies every outside variable the body uses |
| [&] | refers to every outside variable the body uses |
| [this] | lets a lambda inside a member function use the object's members |
| [total = 0] | init-capture: makes a new variable inside the lambda (C++14) |
int count = 0;
auto byRef = [&count]() { ++count; };
byRef(); byRef();
std::cout << count << '\n'; // 2
int base = 10;
auto byValue = [base]() { return base * 2; };
base = 100;
std::cout << byValue() << '\n'; // 20: the copy was taken when the lambda was made
auto counter = [n = 0]() mutable { return ++n; };
std::cout << counter() << counter() << '\n'; // 12Generic lambdas and std::function
auto show = [](const auto& x) { std::cout << x << '\n'; }; // C++14 generic lambda
show(42);
show("Namaste");
#include <functional>
std::function<double(double)> taxFor = [](double p) { return p * 0.18; };
taxFor = [](double p) { return p * 0.05; }; // can hold any callable with that signatureWhere lambdas appear
- Comparators: std::sort(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.price < b.price; });
- Predicates: std::find_if, std::any_of, std::erase_if, std::remove_if.
- Callbacks: run this when a button is clicked or a download finishes.
- Threads: std::thread t([] { doWork(); });
- Immediately invoked initialisation: const int limit = [&] { /* complex logic */ return 5; }();
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Lambdas: small functions written in place · 1/6
A lambda is a small function written right where you need it.
Prefer a video by a teacher? Find free videos on “c++ lambda expressions capture by value reference tutorial” on YouTube ↗
In real life: Filtering a product catalogue
A shopping app filters products by the user's choices: price range and minimum rating. The filter values come from the screen, so the lambda captures them, and std::copy_if builds the filtered list. Sorting by price uses another lambda.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
struct Product { std::string name; int price; double rating; };
int main() {
std::vector<Product> all = {{"Earbuds", 1299, 4.1}, {"Speaker", 2499, 4.5},
{"Cable", 199, 3.9}, {"Charger", 899, 4.4}};
int maxPrice = 2000;
double minRating = 4.0;
std::vector<Product> shown;
std::copy_if(all.begin(), all.end(), std::back_inserter(shown),
[maxPrice, minRating](const Product& p) {
return p.price <= maxPrice && p.rating >= minRating;
});
std::sort(shown.begin(), shown.end(), [](const Product& a, const Product& b) { return a.price < b.price; });
for (const auto& p : shown) std::cout << p.name << ' ' << p.price << '\n';
}
// Charger 899
// Earbuds 1299Practice (0/4 done)
What does this print? auto sq = [](int x) { return x * x; }; std::cout << sq(6);
What does this print? int k = 1; auto f = [k]() { return k + 1; }; auto g = [&k]() { return k + 1; }; k = 10; std::cout << f() << " " << g();
Which line has the bug? 1: std::function<int()> make() { 2: int total = 5; 3: return [&total]() { return total; }; 4: }
Given std::vector<std::string> names, use lambdas with algorithms to: (1) count names longer than 5 letters, (2) sort names by length, shortest first, ties alphabetically, (3) remove names starting with 'A' using std::erase_if. Print the results.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- auto, structured bindings and other C++17 conveniencesModern C++: lambdas, C++17 and C++20 essentials · same module
- std::optional, std::variant and std::string_viewModern C++: lambdas, C++17 and C++20 essentials · same module
- C++20 ranges, views and other C++20 essentialsModern C++: lambdas, C++17 and C++20 essentials · same module
- Lambdas and higher-order functionsKotlin and Android App Development · Null safety, functions and lambdas
- Delegates, lambdas, Func, Action and PredicateC# and .NET · Exceptions, delegates, events and async
- Lambdas and functional interfacesJava Programming (Core to Spring Boot) · Lambdas, streams and files
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does [=] capture?
Answer: Every outside variable used in the body, by copy
[=] is a default capture by value.
Why is mutable needed in [n = 0]() mutable { return ++n; }?
Answer: Captured copies are const by default; mutable allows changing them
Without mutable, ++n would not compile.
What makes a lambda "generic"?
Answer: It uses auto in its parameter list
auto parameters turn the call operator into a template.
Which is a downside of std::function compared with auto?
Answer: It has some run-time overhead (type erasure, possible allocation)
std::function is flexible but costs more than calling the lambda directly.
What is the result of a lambda?Related
Answer: The value of its last expression
The last expression is returned automatically.
In Func<string, int>, what is the return type?Related
Answer: int
The last type parameter of Func is the return type.
What is the time complexity of std::sort?Related
Answer: O(n log n)
The standard requires O(n log n) comparisons.
From STL algorithms: sort, find, count, accumulate and binary search
When did lambdas arrive in Java?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Modern C++: lambdas, C++17 and C++20 essentials” before its exam: auto, structured bindings and other C++17 conveniences, std::optional, std::variant and std::string_view, C++20 ranges, views and other C++20 essentials.
- Module 8 exam: Modern C++ · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Exceptions, concurrency and building projects with CMake. 42 topics left in the course before the final exam.