Метапрограммирование препроцессора C: заменить макрос не в списке аргументов
Этот вопрос касается «метапрограммирования препроцессора C», то есть таких вещей, как это, это, это, это и т. Д.
Я пишу нетривиальную метапрограмму препроцессора C, которая, в частности, должна рекурсивно "вызывать" макросы (используя стандартнуюDEFER
/EVAL
трюки), и эти макросы должны будут объявить переменные:
#define F(x, y) \
do { \
int var; \
\
/* ... */ \
\
DEFER(F)()(var, y) \
} while (0)
Однако это создает переменную, затеняющую переменные во внешних областях, что является проблемой, если мне нужно передатьvar
себя как один из параметров (т. е. рекурсивный «вызов», необходимый для доступа к var в предыдущей области видимости). Решение, которое я нашел, состояло в том, чтобы объединить символ, такой как_
на каждом уровне рекурсии:
#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y
#define F(x, y, l) \
do { \
int CAT(var, l); \
\
/* Code that uses CAT(var, l) extensively */ \
\
DEFER(F)()(CAT(var, l), y, CAT(l, _)); \
} while (0)
Итак, если предположить, что первоначальный «вызов»F()
имеет формуF(x, y, _)
, затемvar_
будет объявлено; на первом уровне рекурсии,var__
будет объявлено; В секунду,var___
, и так далее.
Это работает, но код замусорен вхождениямиCAT(var, l)
делая его еще более нечитаемым, чем такой код обычно уже есть. Я ищу наиболее компактный синтаксис, чтобы сделать код немного менее нечитаемым, т.е. что-то вродеV(var)
, без необходимости расшифровывать, l
часть явно.
Однако у меня возникли проблемы с написанием макроса, чтобы это работало (при условии, что это вообще возможно).
Вот MRE, который даже не является действительной программой C, но продемонстрирует то, что я ищу, если запустить только препроцессор, т.е. используяgcc -E
:
#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y
#define F1(x, l) CAT(x, l)
#define CATL(x) CAT(x, l)
#define F2(x, l) CATL(x)
F1(var, _)
F2(var, _)
Результат предварительной обработки этого (удаление мусора в начале):
var_
varl
То, что я хотел бы, это версияCATL()
с одним параметром макроса (т.е. без явной передачи в качестве параметра), но все еще "захваченным"l
, чтобы вместо этого получить следующий вывод:
var_
var_