recursive lambda


Вот бывает же такое, что выходишь из дома прямо в солнечный теплый день. Птички весело поют, а не воют от беспросветного ужаса вечной стужи. Распускается сирень. Солнце входит в силу, одним своим видом заставляя барышень радостно скидывать одежду. Искусство, тебе недоступное, но совершенно бесполезно об этом переживать. Наше светило все любят, а тебя - нет. Впрочем ничто уже не способно испортить хорошее настроение, даже притаившиеся во дворе грузовички Теплоэнерго. Вдруг остановишься, поглядишь на все это великолепие и подумаешь: "А если лямбду вызывать внутри этой же лямбды, вот был бы номер!"
Не бывало? Странно, следовало бы задуматься.
К сожалению, а может, и к счастью, это непросто сделать. Лямбда обладает плохой рефлексией в этом смысле и не может ссылаться на саму себя как на объект. Слово this для нее пустой звук, если не фигурирует в захвате. Попытка его использовать приведет лишь к чему-то подобному:
𝖾𝗋𝗋𝗈𝗋: 𝗂𝗇𝗏𝖺𝗅𝗂𝖽 𝗎𝗌𝖾 𝗈𝖿 '𝗍𝗁𝗂𝗌' 𝗂𝗇 𝗇𝗈𝗇-𝗆𝖾𝗆𝖻𝖾𝗋 𝖿𝗎𝗇𝖼𝗍𝗂𝗈𝗇 [-𝖶𝗍𝖾𝗆𝗉𝗅𝖺𝗍𝖾-𝖻𝗈𝖽𝗒]
Что же, нас в дверь, а мы в окно. Если попробовать явно захватить указатель на самого себя?
𝚊𝚞𝚝𝚘 𝚡 = [&𝚡] (𝚒𝚗𝚝 𝚊) -> 𝚟𝚘𝚒𝚍 {
𝚒𝚏 (𝚊) { 𝚡(--𝚊); }
};
Выглядит неплохо, однако GCC не совсем понимает, чего мы от него хотим.
𝚎𝚛𝚛𝚘𝚛: 𝚞𝚜𝚎 𝚘𝚏 '𝚡' 𝚋𝚎𝚏𝚘𝚛𝚎 𝚍𝚎𝚍𝚞𝚌𝚝𝚒𝚘𝚗 𝚘𝚏 '𝚊𝚞𝚝𝚘'
В самом деле, представьте себя компилятором, которому втирают какую-то дичь. Ты пытаешься под эту дичь создать класс:
𝚌𝚕𝚊𝚜𝚜 𝚜𝚞𝚙𝚎𝚛_𝚍𝚛𝚞𝚙𝚎𝚛_𝚕𝚊𝚖𝚋𝚊 {
𝚙𝚞𝚋𝚕𝚒𝚌:
𝚒𝚗𝚝 𝚘𝚙𝚎𝚛𝚊𝚝𝚘𝚛()(𝚒𝚗𝚝 𝚊) 𝚌𝚘𝚗𝚜𝚝 {
𝚒𝚏 (𝚊) { 𝚡(--𝚊); }
}
𝚙𝚛𝚒𝚟𝚊𝚝𝚎:
?𝚝𝚢𝚙𝚎? 𝚡;
};
Так-так-так, а какой тип у нашего захваченного x? Элементарно, надо инстанцировать лямбду, и тип станет понятен. Стоп, а я чем сейчас занимаюсь?
В общем, попал компилятор в замкнутый круг трансцендентной апперцепции.
Однако можно явно указать тип переменной:
𝚜𝚝𝚍::𝚏𝚞𝚗𝚌𝚝𝚒𝚘𝚗<𝚟𝚘𝚒𝚍(𝚒𝚗𝚝)> 𝚢 = [&𝚢](𝚒𝚗𝚝 𝚊) { ... };
Здесь уже захватывается не полуфабрикат лямбды, а ссылка на понятный тип std::function<void(int)>, к которому лямбда может быть приведена.
Да, такое сработает, но опасайтесь висячих ссылок. Ну и использование std::function стандарты безопасности не одобрят.
Хорошо, если можно обойтись без захватов, тогда лямбду можно выставить статической:
𝚜𝚝𝚊𝚝𝚒𝚌 𝚟𝚘𝚒𝚍(*𝚣)(𝚒𝚗𝚝) = [](𝚒𝚗𝚝 𝚊) {
𝚒𝚏 (𝚊) { 𝚣(--𝚊); }
};
Да, статические переменные видны внутри и без захватов. Главное, что тип z здесь известен заранее. Для auto это не вариант.
Для него есть только такая возможность:
𝚊𝚞𝚝𝚘 𝚡 = [] (𝚊𝚞𝚝𝚘 &𝚜𝚎𝚕𝚏, 𝚒𝚗𝚝 𝚊) -> 𝚟𝚘𝚒𝚍 {
𝚒𝚏 (𝚊) { 𝚜𝚎𝚕𝚏(𝚜𝚎𝚕𝚏, --𝚊); }
};
Передача функции через параметр self сработает только при условии явного указания результирующего типа, а то компилятор опять не может сообразить, что за тип у лямды.
Как мы видим, извращенный мозг разработчика обошел и проблему рекурсивного вызова лямбды, но все равно эти методы отдают каким-то колхозом.
Просмотры: 22
Открыть в MAX Сообщить о неточности

Репосты публикации

Публикация канала

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти