Будет работать следующий код:
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
int foo = EVAL2(MYLIST(AA)) 0;
Вывод: int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
К сожалению, у меня нет глубокого понимания , почему это работает;Я только что попробовал несколько трюков, которые, как правило, помогают в подобных случаях.Но я могу объяснить кое-что из этого.
Иногда макрос помечается как «не подлежащий дальнейшему расширению».Флаг обычно устанавливается, когда вы начинаете расширять его, и сбрасывается, когда расширение заканчивается.Это имеет тенденцию предотвращать рекурсию.
Когда макрос раскрывается в токены, которые обычно были бы функциональными вызовами макросов, иногда мы уже прошли этап, на котором они были бы расширены.
Мыможет обойти первую проблему, отложив развертывание макроса до точки, где флаг не вызовет никаких проблем, добавив второй макрос в create вызов макроса при его оценке.Вот что делает DELAYED_CALL
.Но при этом мы сталкиваемся со второй проблемой, поэтому нам нужно добавить несколько вызовов к EVAL
, чтобы вызвать повторное сканирование макроса (аргументы к функционально-подобному макросу всегда сканируются, поэтому передается последовательность токеновфункционально-подобный макрос, который просто выводит свои аргументы, вызывает повторное сканирование).
Иногда нам требуется пара повторных проверок, чтобы все работало.EVAL2(X)
это просто сокращение для EVAL(EVAL(X))
.Иногда потребуется больше уловок.
Приведенный ниже код немного проясняет происходящее.Обратите внимание, что версии MYLIST2 требуется на один меньше EVAL;это связано с тем, что AA вызывает MYLIST, а MYLIST2 имеет установленный флаг сбоя.
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EVAL3(...) EVAL2(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
#define MYLIST2(XX) \
XX(1, hello) \
XX(2, world)
% MYLIST
int foo = MYLIST(AA) 0;
int foo = EVAL(MYLIST(AA)) 0;
int foo = EVAL2(MYLIST(AA)) 0;
% MYLIST2
int foo = MYLIST2(AA) 0;
int foo = EVAL(MYLIST2(AA)) 0;
int foo = EVAL2(MYLIST2(AA)) 0;
Вывод этого будет:
% MYLIST
int foo = AA (1, hello) AA (2, world) 0;
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
% MYLIST2
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
(Знаки% aren 'Ничего особенного. Я просто хотел, чтобы комментарии выводились в выводе, а комментарии в стиле C удалялись во время предварительной обработки.)
Дальнейшее чтение .Автор статьи понимает это гораздо лучше, чем я.