Лямбда-функция
Имеет следующий синтаксис:
auto lambda = [](int a, int b) {return a < b;}
Полученный объект по сути является структурой с известным только компилятору уникальным типом, имеющим operator()
с аргументами, которые передаются в лямбду.
Возвращаемый тип можно задать явно через trailing return types, либо довериться компилятору (равносильно типу auto).
Квадратные скобки здесь не просто для красоты - они используются для захвата переменных из контекста объявления лямбда-функции:
int a = 42;
// захват переменной по значению
auto mul = [a](int k) {return k * a;}
// захват переменной по ссылке
auto add = [&a](int k) {return k + a;}
// захват переменной по значению с присвоением нового имени (C++14)
auto sub = [b = a](int k) {return k - b;}
// захват переменной по ссылке с присвоением нового имени (C++14)
auto div = [&b = a](int k) {return k / b;}
Также лямбды умеют делать захват всего контекста по значению или ссылке:
int x, y;
[=](){} // все по значению
[=, &x](){} // все по значению, x - по ссылке
[&](){} // все по ссылке
[&, x](){} // все по ссылке, x - по значению
Захваченные по значению объекты являются константными, если лямбда-функция не имеет спецификатора mutable
. Также можно захватывать this
, как указатель на объект, где лямбда была объявлена, а можно захватывать *this
, как копию объекта.
Свойства лямбд
- могут копироваться и перемещаться
- не могут присваиваться
- лямбды без захвата могут конвертиться к указателю на функцию
- при копировании лямбды копируются все захваченные по значению переменные
- захват по ссылке не продлевает время жизни объектов. Такой код работает неправильно:
auto foo() {
std::vector<int> v;
return [&v]() {
// ...
};
} // v уничтожится при выходе из функции, обращение внутри лямбды - UB
Начиная с C++20 лямбды могут иметь шаблонные параметры:
int main() {
auto less = []<typename T>(T a, T b) {return a < b;};
bool val = less(42, 43);
}
Рекурсивный вызов лямбды
Пример ниже выдаст ошибку компиляции:
auto factorial = [&factorial](int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
};
error: use of 'factorial' before deduction of 'auto'
, что говорит нам о том, что тип auto
еще не был выведен, поэтому пользоваться им нельзя.
Вариант 1
std::function<int(int)> factorial;
factorial = [&](int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
};
std::cout << factorial(4);
Вариант 2
auto factorial = [](int n, auto&& f) -> int {
return (n <= 1 ? 1 : n * f(n - 1, f));
};
std::cout << factorial(4, factorial);
Заимствования:
cpp-notes/19_lambdas_type_erasure.md at master · lejabque/cpp-notes (github.com)