Делаю рекурсивную лямбда (для определенности - факториал).
Вот так все отлично работает:
std::function f = [&f](int n) -> int { return (n) ? n*f(n-1) : 1; };
А вот так - ни в какую:
auto h = [&h](int n) -> int { return (n) ? n*h(n-1) : 1; };
хотя, казалось бы, тип h вывести нет никакой проблемы - специально даже указал возвращаемы
int. В чем настолько большая разница, что вывод типа не срабатывает? Казалось бы, из определения (int)->int тип очевиден, после чего можно использовать его в теле лямбды?
И второй вопрос - интересно, а можно ли извратиться до такой степени, чтобы написать анонимную рекурсивную лямбду, т.е. без сохранения ее в переменной - что-то вроде
cout << [&](int n)->int{ ..... }(6) << endl;
P.S. Решение для второго вопроса нашлось - использовать внутри неименованной лямбды именованную (например, тот же f выше), но это все же не совсем то, что хотелось :)
Ответы
Ответ 1
Разыграем спектакль, главные действующие лица: компилятор и компилятор, и компилятор, и ... Компилятор встречает следующую строчку:
auto h = [&h](int n) -> int { return (n) ? n*h(n-1) : 1; };
— Ага — говорит, компилятор. Мне нужно сгенерировать класс под лямбду, секундочку:
class lkdlkhbahbahkl_danfaksdf_lamba
{
public:
int operator(int n) const
{
return (n) ? n*h(n-1) : 1;
}
private:
???? h;
};
Компилятор встречает первое препятствие, нужно объявить член класса с именем h, но его тип не известен. Надо спросить компилятор!
— Компилятор, скажи мне тип переменной h! — воскликнул компилятор.
— Секундочку — ответил компилятор. А сам подумал, я ведь тип то и не знаю, спрошу-ка я компилятор, что там за тип у этой лямды.
— Компилятор, скажи мне тип лямбды, у меня компилятор спрашивает, ему надо там член класса создать, а он тип не знает — говорит компилятор
— Нет проблем — отвечает компилятор, сейчас, только лямбду сгенерирую...
Ну Вы поняли, как наш спектакль будет продолжен?
Касательно второго вопроса: анонимную рекурсивную лямбду создать нельзя. Если что-то не имеет имени, как сделать рекурсивный вызов?
Ответ 2
Начиная с С++14, аргументы в лямбда-выражениях могут использовать вывод типов (генерируется шаблонный operator()):
[](auto f) { f(); }
Это позволяет использовать continuations (продолжения) в лямбда-выражениях:
auto fac = [](int n) {
auto impl = [](int n, auto continuation) {
if (n < 2) return 1;
return n * continuation(n - 1, continuation);
};
return impl(n, impl);
};
Комментариев нет:
Отправить комментарий