Заменить родительские токены в дочернем макросе

Я хочу заменить некоторые токены в вызываемом макросе, но не могу определить правильный порядок расширения и \ или отсрочки. Например:

#define EXPAND(...) __VA_ARGS__
#define REPLACE(hello,y) EXPAND(y)
REPLACE(goodbye, hello world)

На мой взгляд, макрос REPLACE будет вызывать макрос EXPAND, что делает его функционально идентичным:

#define REPLACE(hello,y) hello world

Позволяя превратить hello world в goodbye world.

Мой компилятор (MSVC 2017), похоже, этого не делает, поэтому я подозреваю, что здесь я ошибаюсь. Я читал о расширении и отсрочке и пробовал много разных комбинаций DEFER() и EXPAND(), но, похоже, ни одна из них не дает результата, который мне нужен.

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


person lucasz    schedule 29.03.2019    source источник
comment
Вы не можете использовать макросы для создания макросов. Единственный способ решить эту проблему - использовать два уровня предварительной обработки. Возможно, если бы вы могли расширить свой вопрос, чтобы он был о почему вы хотите это сделать, в чем может быть реальная проблема, которую вы пытаетесь решить, тогда мы могли бы помочь вам с этим вместо этого. ?   -  person Some programmer dude    schedule 29.03.2019
comment
Да, я знаю, что макросы не могут создавать другие макросы ... это была плохая формулировка с моей стороны. Немного изменена формулировка. Публикация цели для этой системы довольно запутанна и сделает неясным сам вопрос. Я понимаю, что контекст иногда помогает с вопросами, но я думаю, что в данном случае все, что нужно, - это дистиллированная версия.   -  person lucasz    schedule 29.03.2019
comment
Мне непонятно, чего вы хотите добиться. Если у вас есть макрос-вызов типа REPLACE(goodbye, hello, world) (обратите внимание на запятые), то довольно легко заменить hello на goodbye. Это то, что вы хотите?   -  person Lundin    schedule 29.03.2019
comment
Отсюда вы не можете добраться ... расширения макросов работают не так, как вы предполагаете. Когда вызывается REPLACE(goodbye, hello world), первым шагом является принятие параметров, упомянутых в списке замены (y в EXPAND(y); не имеет значения, что это в круглых скобках), и замена их соответствующими аргументами (после раскрытия, что является пустым звуком, поскольку ни один hello и goodbye не являются объектными макросами). Это приводит к EXPAND(hello world). Как только все это будет сделано, результат будет повторно сканирован, и в этот момент EXPAND распознается как вызов, вызывающий рекурсию.   -  person H Walters    schedule 29.03.2019
comment
... есть способы обнаружения шаблонов и выполнения замен, но они включают в себя разные подходы. Невозможно порекомендовать один, если мы не знаем, с какой реальной проблемой вы пытаетесь справиться.   -  person H Walters    schedule 29.03.2019


Ответы (1)


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

Вот фактический алгоритм подстановки из 6.10.3.1/1 [Подстановка аргументов] стандарта C:

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

Обратите внимание, что аргументы макроса заменяются перед помещением в раскрытие макроса. После этого имена параметров в списке замены больше не актуальны и не являются частью заменяемого текста.

После того, как вызов макроса был заменен его раскрытием, полученные токены затем сканируются снова (6.10.3.4: «Результирующая последовательность токенов предварительной обработки затем повторно проверяется вместе со всеми последующими токенами предварительной обработки исходного файла, чтобы найти дополнительные имена макросов для замены. . "). Однако, поскольку вызов макроса был полностью заменен перед повторным сканированием, токены параметров больше не отображаются.

Так что это конкретное решение вашей проблемы тупиковое. Я рекомендую вам вернуться на шаг назад и сосредоточиться на проблеме, которую вы действительно хотите решить.

person rici    schedule 29.03.2019
comment
Оглядываясь назад, можно сказать, что часть о безопасности макросов имеет смысл. Спасибо за вашу помощь! - person lucasz; 30.03.2019