Comments 15
Забавная, конечно, дичь. Практическое применение я смог придумать только примеру №3. Можно забабахать такую-себе ручную таблицу виртуальных функций вне контекста класса. Не знаю зачем, но можно.
Автор оригинала забыл опустить наверное самую важную особенность лямбд, введённую с C++14 -- это generic lambda. В сочетании с fold expression (c++ 17) можно теперь не городить лютые шаблоны, а делать всё куда лакончинее и проще:#include <iostream>
#include <string>
int main()
{
auto sum = [](auto x, auto y, auto... args)
{
return ((x + y) + ... + args);
};
//prints: 8
std::cout << sum(3, 5) << std::endl;
//prints: hello world one two
std::cout << sum(std::string{"hello "}, "world ", "one ", "two") << std::endl;
return 0;
}
Фактически, лямбды стали синтаксическим сахаром над шаблонными функторами.
Мы на курсе делали интерпретатор упрощенного аналога Python. Там как раз функциональные объекты (выражения) сначала добавлялись в контейнер, а потом последовательно из него вызывались. Та была еще задачка.
Как обычно, переводчик изнасиловал статью:
Общие лямбды и их вывод
Возвращение лямбды
Вот пример аналога рекурсивной лямбда-функции без std::function
:
struct {
void operator()() {
return (*this)();
}
} recusive_lambda;
recursive_lambda();
Да, это анонимная структура, но после компиляции останется лишь вызов перегрузки оператора, результат будет идентичен объявлению и вызову обычной лямбда-функции, но теперь у нас есть указатель this
... но вот только теперь мы жертвуем лямбда-захватом, что в принципе сложно эмитировать при некоторых обстаятельствах. Кстати этот вариант лямбды можно засунуть в std::function
, а следовательно и передовать в аргументы других функций, главное чтобы сигнатура перегрузки оператора совпадала с сигнатурой объявленной в std::function
А можно поподробнее по поводу: Хранение лямбд в контейнере + Возможно, это не совсем правильно... + можно сделать небольшой хак и хранить все лямбды как объекты std::function
?
Я себя данный подход использую во всю. Почему это не совсем правильно? почему хак? Я не прав так делая? Какие подводне камни здесь есть?
Рекурсивные лямбды - это, внезапно, именно то, как делаются рекурсивные функции в лямбда-исчислении. С помощью Y-комбинатора.
Как по-быстрому и по-красивому прикрутить сюда карринг, у меня сейчас фантазии не хватило, поэтому фиг с ним, пусть будет бойлерплейт с вызовом g(g,....).
auto Y = [](auto f) { return [f](auto x) { return f(f, x); }; };
int main() {
auto fac = Y([](auto g, unsigned k) -> unsigned { return k==0 ? 1 : k*g(g, k-1); });
printf("%u", fac(5));
}
Шел 2021 год. Я зык C++ медленно но верно деградировал в perl, где вместо того чтобы разбираться что хотел сказать тем или иным кодом очередной шизофреник было легче его переписать.
auto CreateLambda(int y) {
return [&y](int x) { return x + y; };
}
Тут мы точно хотим захватывать y по ссылке?
Есть предложение в стандарт, которое вероятно попадет в ближайшие версии C++, в нем вводятся рекурсивные лямбды - self
это неявный аргумент, являет собой объект closure.
auto fib = [](this auto self, int n) {
if (n < 2) return n;
return self(n-1) + self(n-2);
};
5 любопытных примеров лямбд в C++: рекурсия, constexpr, контейнеры и многое другое