Lesson 11 · 11 of 20
Lambdas and captures · C++
Write functions on the spot with C++ lambdas: sort tasks, capture variables by value or by reference, and use mutable and auto parameters.

A lambda is an unnamed function written right where it is needed: [captures](parameters) { body }. byPriority compares two tasks by priority and is passed to std::stable_sort, which orders them from highest to lowest and keeps the original order for equal priorities ("Fix login" before "Review PR").
The square brackets hold the captures, the outside variables the lambda may use. [budget, &planned] captures budget by value (a copy, which cannot be changed inside) and planned by reference, with &: when fits adds hours, it changes the variable in main. That is how tasks are planned until the 4 hours are full, and "Write docs" is left for later.
A lambda that captures by value cannot modify its copy unless it is marked `mutable`. nextTicket keeps its own counter, starting at 100 and giving 101 and 102, while main's ticket stays at 100. There are also [=] (everything by value) and [&] (everything by reference), although naming each variable is clearer.
With auto parameters you get a generic lambda, which behaves like a template: twice(21) gives 42 and twice(std::string("ha")) gives "haha". Every lambda has its own type that only the compiler knows, which is why it is stored in an auto variable.
Code · main.cpp
#include <algorithm>#include <iostream>#include <string>#include <vector>struct Task { std::string title; int priority; double hours; };int main() { std::vector<Task> tasks = {{"Fix login", 3, 2.5}, {"Write docs", 1, 4}, {"Release", 5, 1}, {"Review PR", 3, 0.5}}; // A lambda is a function written in place: [captures](parameters) { body }. auto byPriority = [](const Task& a, const Task& b) { return a.priority > b.priority; }; std::stable_sort(tasks.begin(), tasks.end(), byPriority); // [budget] copies the variable; [&planned] works on the original. double budget = 4.0, planned = 0; auto fits = [budget, &planned](const Task& t) { if (planned + t.hours > budget) return false; planned += t.hours; return true; }; for (const Task& t : tasks) std::cout << (fits(t) ? "[today] " : "[later] ") << t.title << " (p" << t.priority << ")\n"; std::cout << "Planned: " << planned << " of " << budget << " hours\n"; // mutable lets a lambda change its own copy of a captured value. int ticket = 100; auto nextTicket = [ticket]() mutable { return ++ticket; }; int a = nextTicket(), b = nextTicket(); std::cout << "Tickets " << a << " and " << b << ", but ticket is still " << ticket << "\n"; auto twice = [](auto x) { return x + x; }; // generic lambda: auto parameter std::cout << twice(21) << " " << twice(std::string("ha")) << "\n";}Output · c++ -std=c++17 main.cpp -o main && ./main
[today] Release (p5) [today] Fix login (p3) [today] Review PR (p3) [later] Write docs (p1) Planned: 4 of 4 hours Tickets 101 and 102, but ticket is still 100 42 haha
Key points
- A lambda is
[captures](parameters) { body }. [x]copies the variable;[&x]works on the original.mutablelets a lambda change its by-value copy.- With
autoparameters, the lambda is generic. - Lambdas are ideal for passing criteria to
sortand other algorithms.
Exercise
Set the budget to 3 hours and add a byHours lambda that sorts from fewest to most hours. Plan with that order and compare how many tasks fit now.