Страницы

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

понедельник, 1 октября 2018 г.

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

Делаю рекурсивную лямбда (для определенности - факториал). Вот так все отлично работает:
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 выше), но это все же не совсем то, что хотелось :)


Ответ

Разыграем спектакль, главные действующие лица: компилятор и компилятор, и компилятор, и ... Компилятор встречает следующую строчку:
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! — воскликнул компилятор.
— Секундочку — ответил компилятор. А сам подумал, я ведь тип то и не знаю, спрошу-ка я компилятор, что там за тип у этой лямды.
— Компилятор, скажи мне тип лямбды, у меня компилятор спрашивает, ему надо там член класса создать, а он тип не знает — говорит компилятор
— Нет проблем — отвечает компилятор, сейчас, только лямбду сгенерирую...
Ну Вы поняли, как наш спектакль будет продолжен?

Касательно второго вопроса: анонимную рекурсивную лямбду создать нельзя. Если что-то не имеет имени, как сделать рекурсивный вызов?

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

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