DMarlon Studio

Lección 11 · 11 de 20

Lambdas y capturas · C++

Escriba funciones en el sitio con las lambdas de C++: ordene tareas, capture variables por valor o por referencia y use mutable y auto.

C++ · Lambdas y capturas en DMarlon Studio: el código del ejemplo y su salida en la terminal

Una lambda es una función sin nombre escrita justo donde se necesita: [capturas](parámetros) { cuerpo }. byPriority compara dos tareas por prioridad y se pasa a std::stable_sort, que las ordena de mayor a menor y, a igual prioridad, respeta el orden original («Fix login» antes que «Review PR»).

Entre corchetes van las capturas, las variables de fuera que la lambda puede usar. [budget, &planned] captura budget por valor (una copia, que dentro no se puede cambiar) y planned por referencia, con &: cuando fits suma horas, cambia la variable de main. Así se planifican tareas hasta llenar las 4 horas, y «Write docs» se queda para más tarde.

Una lambda que captura por valor no puede modificar su copia, salvo que se marque `mutable`. nextTicket lleva su propio contador, que empieza en 100 y da 101 y 102, mientras el ticket de main sigue en 100. También existen [=] (todo por valor) y [&] (todo por referencia), aunque es más claro nombrar cada variable.

Con auto en los parámetros se obtiene una lambda genérica, que funciona como una plantilla: twice(21) da 42 y twice(std::string("ha")) da «haha». Cada lambda tiene un tipo propio que solo conoce el compilador; por eso se guarda en una variable auto.

Código · 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";}

Salida · 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

Para recordar

  • Una lambda es [capturas](parámetros) { cuerpo }.
  • [x] copia la variable; [&x] trabaja con la original.
  • mutable deja cambiar la copia capturada por valor.
  • Con parámetros auto, la lambda es genérica.
  • Las lambdas son ideales para pasar criterios a sort y a los algoritmos.

Ejercicio

Cambie el presupuesto a 3 horas y añada una lambda byHours que ordene por horas, de menos a más. Planifique con ese orden y compare cuántas tareas caben ahora.