Day 37.
Иногда можно хулиганить.
Как????
Сейчас расскажу.
Давайте возьмём такой странный пример:
#define SCAN(...) __VA_ARGS__
#define EMPTY()
#define LOOP_INDIRECTION() LOOP
#define LOOP(x) x LOOP_INDIRECTION EMPTY()() (x)
SCAN вы знаете. EMPTY() раскрывается в пустоту. А два последних понятно во что раскрываются. Там прям справа написано. Но как это работает, мы сейчас рассмотрим. Давайте сначала поймём, во что раскроется
LOOP(1):
LOOP(1)
// 1 LOOP_INDIRECTION EMPTY()() (1)
// 1 LOOP_INDIRECTION EMPTY()() (1) // раскрываем EMPTY()
// 1 LOOP_INDIRECTION () (1)
Вот тут важный момент: между
LOOP_INDIRECTION и () есть пробел. А значит препроцессор воспринимает это как два отдельных токена. из-за чего раскрывать LOOP_INDIRECTION() он не станет. Так что мы на этом останавливаемся. Теперь давайте просканируем:
SCAN(LOOP(1))
// SCAN(1 LOOP_INDIRECTION () (1))
// 1 LOOP_INDIRECTION()(1) // токены рассматриваются как один поток
// 1 1 LOOP_INDIRECTION () (1)
То есть получили уже 2 единицы в начале.
Обобщая идею можно реализовать
EVAL:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) __VA_ARGS__
И для
EVAL(LOOP(1));
мы получим единицы на всю глубину EVAL:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 LOOP_INDIRECTION ()(1)
Можно в итоге написать макрос, которые из
E3(LOOP(f,1,2,3,4,5,6,7,8,9,END))
раскроется в
// f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9)
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.