Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Рекурсивная лямбда


Делаю рекурсивную лямбда (для определенности - факториал).
Вот так все отлично работает:

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); };

Комментариев нет:

Отправить комментарий