Перейти к содержимому
Теория · Функции · урок 9 из 11

Лямбды: первое знакомство

Определить функцию внутри другой функции нельзя: int twice(int x) { return x * 2; } внутри main компилятор не примет. Но короткая функция часто нужна в одном месте, и выносить её из main неудобно. Такую функцию можно записать прямо там, где она нужна, — лямбдой (lambda):

C++
#include <iostream>

int main() {
    auto twice = [](int x) { return x * 2; };
    std::cout << twice(21) << '\n';  // 42
}

Устройство лямбды

Лямбда — функция без имени, записанная прямо внутри выражения. Квадратные скобки [] начинают лямбду, в круглых скобках стоят параметры, в фигурных — тело. Тип результата компилятор выводит из return, как тип auto-переменной — из её значения. В примере x * 2 имеет тип int, поэтому и лямбда возвращает int.

Лямбду сохраняют в переменную, объявленную через auto: тип у лямбды есть, но назвать его в коде нельзя. Каждая лямбда получает свой тип, который придумывает компилятор. Вызывают лямбду по имени переменной, как обычную функцию: twice(21). Параметры у лямбды такие же, как у функции, — по значению или по ссылке.

Захват переменных

Чтобы лямбда могла использовать локальную переменную step из main, переменную нужно захватить. Захват (capture) — переменные, которые лямбда берёт из окружающего кода; их перечисляют в квадратных скобках. [step] копирует step в момент создания лямбды, а [&step] даёт лямбде ссылку на саму step:

C++
#include <iostream>

int main() {
    int step = 10;
    auto add_copy = [step](int x) { return x + step; };
    auto add_ref = [&step](int x) { return x + step; };
    step = 100;
    std::cout << add_copy(1) << ' ' << add_ref(1) << '\n';  // 11 101
}

add_copy хранит копию со значением 10: она сделана, когда выполнялась строка с лямбдой, поэтому изменение step до неё не доходит. add_ref читает саму step, которая к моменту вызова уже равна 100.

Через захват по ссылке лямбда может и менять переменную: [&count]() { ++count; } при каждом вызове увеличивает count из main. Копию из [step] лямбда может только читать: [step]() { ++step; } не скомпилируется. Несколько переменных перечисляют через запятую: [a, &b].

Частая ошибка

Переменную используют в лямбде, но не захватывают:

C++
int main() {
    int step = 10;
    auto add = [](int x) { return x + step; };  // ✗
    return add(1);
}
TEXT
error: variable 'step' cannot be implicitly captured in a lambda with no capture-default specified

Это ошибка компилятора: пустые скобки [] значат, что лямбда ничего не захватывает. Добавьте переменную в захват — [step] или [&step].