Обёртывание вызываемого объекта в лямбду, которая просто вызывает его с теми же параметрами

Предположим, у вас есть функция, которая принимает лямбду и хочет использовать её при вызове другой функции. Я видел, как люди оборачивают лямбду внутрь другой лямбды:

Но нет смысла оборачивать лямбду в другую лямбду, если вы просто вызываете внутреннюю лямбду с теми же параметрами, что и внешняя. Можно напрямую использовать оператор вызова внутренней лямбды.

Моё предположение: некоторые люди не осознают, что лямбда — это не нечто особенное в языке C++. Когда кто‑то говорит, что функция принимает лямбду, они думают, что нужно буквально передать именно лямбду.

В C++ лямбда — это просто синтаксический сахар для класса с оператором вызова функции. И если у вас уже есть класс с оператором вызова функции, нет необходимости оборачивать его в другой класс с тем же оператором вызова.

Оборачивание лямбды — по сути то же самое, что делать это:

Нет нужды вводить дополнительный уровень косвенности. Входящая лямбда уже имеет нужную вам форму. Просто используйте её.

Бонус: оборачивание лямбды имеет смысл, если производится трансформация параметров, например приведение их к определённому типу или принуждение к передаче по значению.

Рэймонд участвует в эволюции Windows более 30 лет. В 2003 году он запустил веб‑сайт под названием The Old New Thing, который стал намного популярнее, чем он мог себе представить, и это по‑прежнему вызывает у него смятение. Веб‑сайт породил книгу, совпадающую по названию с сайтом (Addison Wesley, 2007). Иногда он появляется в аккаунте Windows Dev Docs в Twitter, чтобы рассказать истории, не содержащие полезной информации.

Обсуждение закрыто. Войдите, чтобы редактировать/удалять существующие комментарии.

@BCS Я понимаю, что вы пытаетесь сказать, но не согласен с первоначальным описанием «передать набор перегрузок». Вы прояснили ситуацию в вашем последнем комментарии. Дополнительно считаю, что при явном выборе конкретной функции её следует выбирать с помощью квалифицированного имени, независимо от того, передаётся ли она как аргумент, просто вызывается или обёрнута в лямбду.

@Yexuan Xiao: Я в замешательстве. Не из‑за того, что вы пишете, а из‑за того, почему вы это делаете. Похоже, вы соглашаетесь со всем, что я написал (если это так — круто), но при этом кажется, будто вы либо не согласны, либо пытаетесь что‑то объяснить (но при этом не добавляете ничего, чего бы я уже не знал).

К слову, я полностью осознаю, что в лямбде ничего магического нет, но как раз в этом и суть моего замечания: работать с именем функции (квалифицированным или нет) иначе, чем вызвать её, очень трудно сделать правильно, поэтому если нужно сделать что‑то ещё, лучшим выбором будет…читать далее@Yexuan Xiao: Я в замешательстве. Не из‑за того, что вы пишете, а из‑за того, почему вы это делаете. Похоже, вы соглашаетесь со всем, что я написал (если это так — круто), но при этом кажется, будто вы либо не согласны, либо пытаетесь что‑то объяснить (но при этом не добавляете ничего, чего бы я уже не знал).

К слову, я полностью осознаю, что в лямбде ничего магического нет, но как раз в этом и суть моего замечания: попытки сделать с именем функции что‑то, кроме простого вызова, очень трудно реализовать правильно, так что если вам нужно сделать что‑то другое, лучше использовать лямбду, чтобы принудительно превратить это «что‑то другое» в простой вызов. Коротко: ещё один случай, когда обёртывание единственного вызова функции в лямбду полезно.

Мой комментарий — ответ вам, и я очень рад, что никто из нас не пропустил сообщение другого. Ваше наблюдение верно: ADL работает только для неквалифицированных выражений вызова функции, и static_cast не участвует в этом процессе. ADL определяет, где искать функции; когда он действует, он формирует набор перегрузок. В C++ набор перегрузок — это коллекция кандидатов функций в одной и той же области видимости (пожалуйста, забудьте про «using namespace»). Использование static_cast для выбора функции из набора перегрузок подразумевает, что вы точно знаете области видимости, в которых эти функции находятся. Неквалифицированное выражение вызова функции внутри лямбды применяет ADL, так что здесь нет какого‑то специального правила, связанного с лямбдами.

BCS и Yexuan Xiao, вам может быть интересно знать, что существуют предложения по добавлению новых возможностей в язык C++ для работы с наборами перегрузок, таких как declcall (для ADL) и трактовка наборов перегрузок как функторов. Так что когда‑нибудь мы, возможно, действительно сможем передавать настоящий набор перегрузок вместо лямбды.

@Yexuan Xiao (потому что система комментариев, похоже, теряет, кому предназначён ответ) Ваш комментарий до момента про static_cast соглашается с моей мыслью. Однако когда дело доходит до static_cast, добиться поведения, идентичного вызову, очень трудно. По моему опыту, ADL, похоже, не участвует в static_cast, так что функция, которая была бы вызвана, может даже не быть кандидатом в касте. Также не будут происходить неявные преобразования.

Кроме обёртывания вызова в лямбду, попытки получить указатель на «ту функцию, которую я бы вызвал с этими типами аргументов» вряд ли приведут к чему‑то, кроме разочарования. И это примерно предел того, что C++ поддерживает по работе с наборами перегрузок помимо их вызова.

Снижение раздутия шаблонов C++ путём факторизации зависящих от типа частей функции

Снижение раздутия шаблонов C++ путём факторизации зависящих от типа частей функции, практический экзамен

Получать уведомления о новых публикациях.

Вы уверены, что хотите удалить это?