Lambdas: functions made on the spot
A lambda expression writes a small function right where you need it, for example as the test you hand to std::count_if. The compiler turns it into an object of a hidden class: captured variables become its data, and the body becomes its call operator. Follow one lambda as it copies limit, keeps its 5 when limit changes to 100, and gets called once per element, then see how [&limit] changes the answer and when a reference can dangle.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01In auto big = [limit](int x) { return x > limit; };, what is [limit]?
The square brackets hold the capture list. [limit] captures by copy: the value limit has at that moment is stored inside the closure object.
02int limit = 5; auto big = [limit](int x) { return x > limit; }; limit = 100; What does big(8) return?
A capture by copy is a snapshot taken when the lambda expression ran. Changing limit afterwards does not touch big's copy, which is still 5.
03With v = {3, 8, 1, 9} and the lambda written as [&limit] instead, what does std::count_if(v.begin(), v.end(), big) return after limit = 100?
By reference, big reads main's limit each time it is called. limit is 100 by then, and no element is bigger than 100, so the count is 0.
04What does the compiler make of a lambda expression?
The result of a lambda expression is a closure object. Its class, the closure type, has no name you can write; the body is its operator(), const by default.
05When is capturing by reference dangerous?
A reference is only valid while the variable lives. Calling a closure whose referenced variable is gone is undefined behaviour. Core Guidelines F.52 and F.53: refer for local use, copy when the lambda escapes its scope.
Glossary
- Lambda expression
- An expression such as [limit](int x) { return x > limit; } that writes an unnamed function object in place.
- Closure object
- The object a lambda expression produces. You can copy it, store it in a variable and call it like a function.
- Closure type
- The unnamed class the compiler invents for each lambda expression. Its operator() holds the lambda's body.
- Capture list
- The square brackets at the start of a lambda. They name the variables from around the lambda that it may use.
- Capture by copy
- [x]: the closure stores its own copy of x, made when the lambda expression is evaluated.
- Capture by reference
- [&x]: the closure refers to the original x, so it sees later changes, and must not be used after x is gone.
- Predicate
- A callable that takes a value and answers true or false, such as the test std::count_if uses to decide what to count.
- Generic lambda
- A lambda with an auto parameter (C++14 and later). Its operator() is a template, so one lambda works for many types.
Notes and sources
- The closure type has no name you can write, and the C++ standard leaves its copied members unnamed too. The class Big in the notes is a model that behaves the same way; it is not literally what the compiler writes.
- For a capture by reference the standard does not say whether the closure stores anything (a pointer, say); it only says the lambda refers to the original variable. The figure draws it as a link.
- count_if makes exactly one call per element (four here). The figure walks the vector from first to last, as the usual implementations do.
- The card shows the body of main. The full program adds #include <algorithm>, <iostream> and <vector>, and prints n with std::cout. Built with g++ or clang++ -std=c++20 -Wall -Wextra it prints 2; with [&limit] on line 3 it prints 0.
- std::count_if returns a signed count (the iterator's difference_type, std::ptrdiff_t for a vector), so auto makes n that type rather than int.
- cppreference.com: Lambda expressions
- cppreference.com: std::count, std::count_if
- cppreference.com: Function objects
- Standard C++ Foundation (isocpp.org): C++11 FAQ, Lambdas
- Standard C++ Foundation (isocpp.org): C++14 FAQ, Generic lambdas
- C++ Core Guidelines F.52 and F.53: capturing by reference vs by value
- C++20 working draft N4861: [expr.prim.lambda]
Quiz Unlocks after the last step.