Что такое лямбда-выражение в C++ и когда его нужно использовать?
Что такое лямбда-выражение?
Лямбда-выражение (или просто лямбда) — это анонимная функция, которую вы можете создать прямо в месте использования. В C++11 и новее лямбды стали мощным инструментом для написания компактного и выразительного кода. По сути, это синтаксический сахар над функтором (объектом с перегруженным оператором ()).
Базовая структура лямбды:
[захват](параметры) -> возвращаемый_тип { тело }
Пример простой лямбды:
auto sum = [](int a, int b) { return a + b; };
int result = sum(5, 3); // result = 8
Зачем нужны квадратные скобки [ ]?
Это список захвата (capture list). Он определяет, какие переменные из внешней области видимости будут доступны внутри лямбды и как именно — по значению или по ссылке.
Основные варианты:
[]— ничего не захватываем[x]— захватываемxпо значению[&x]— захватываемxпо ссылке[=]— захватываем все используемые переменные по значению[&]— захватываем все используемые переменные по ссылке[this]— захватываем указатель на текущий объект (для методов класса)[=, &x]— все по значению, кромеx(по ссылке)
Когда использовать лямбду?
Лямбды идеальны в следующих ситуациях:
- Короткие предикаты для алгоритмов STL (сортировка, поиск, фильтрация)
- Обработчики событий и callback-функции
- Временная логика, которая не заслуживает отдельной функции
- Замыкания — когда нужно "запомнить" состояние
Пример с захватом переменной:
int threshold = 5;
std::vector<int> data = {1, 7, 3, 9, 2};
// Захватываем threshold по значению
auto count = std::count_if(data.begin(), data.end(),
[threshold](int x) { return x > threshold; });
// count = 2 (7 и 9)
// Захватываем по ссылке, чтобы изменить
int sum = 0;
std::for_each(data.begin(), data.end(),
[&sum](int x) { sum += x; });
// sum = 22
Когда НЕ стоит использовать лямбду?
- Если логика сложная (больше 5-10 строк) — лучше вынести в именованную функцию
- Если лямбда нужна в нескольких местах — создайте функтор или обычную функцию
- Если важна читаемость и самодокументируемость кода
Продвинутые возможности (C++14 и C++17)
Начиная с C++14 лямбды стали ещё мощнее:
// Обобщённые лямбды (auto параметры)
auto generic = [](auto a, auto b) { return a + b; };
// Захват с инициализацией
auto lambda = [x = std::move(some_value)]() { /* используем x */ };
// constexpr лямбды (C++17)
constexpr auto square = [](int x) { return x * x; };
static_assert(square(5) == 25);
Важные замечания
- Будьте осторожны с захватом по ссылке — убедитесь, что переменная живёт дольше лямбды
- По умолчанию
operator()у лямбды —const, то есть вы не можете изменять захваченные по значению переменные. Используйтеmutableесли нужно:[x]() mutable { x++; } - Лямбды — это объекты, их можно хранить в
std::functionили передавать как шаблонные параметры
Надеюсь, теперь стало понятнее! Лямбды — это мощный инструмент, который делает код на C++ более современным и выразительным. Практикуйтесь, и скоро вы будете использовать их автоматически.
<<Альтернативный взгляд: лямбды как замена функторов
Если вы знакомы с функторами (классами с оператором ()), то лямбды можно рассматривать как их более краткую версию. Сравните:
// Функтор
struct GreaterThan {
int threshold;
GreaterThan(int t) : threshold(t) {}
bool operator()(int x) const { return x > threshold; }
};
std::count_if(v.begin(), v.end(), GreaterThan(5));
// Лямбда (то же самое, но короче)
std::count_if(v.begin(), v.end(), [threshold = 5](int x) { return x > threshold; });
Лямбды особенно удобны, когда нужно создать "одноразовый" функтор прямо на месте. Они избавляют от необходимости писать отдельный класс, что уменьшает количество кода и улучшает читаемость.
Ещё один полезный приём — использование лямбд для отложенного выполнения (lazy evaluation):
auto expensiveCalculation = [](int x) {
// Долгие вычисления
return x * x + 42;
};
// Вычисление произойдёт только при вызове
int result = expensiveCalculation(10);
Совет: если ваш компилятор поддерживает C++20, обратите внимание на шаблонные лямбды с явными параметрами шаблона:
auto lambda = []<typename T>(T a, T b) { return a + b; };
Это даёт ещё больше контроля над типами.