Я создал небольшую библиотеку метапрограммирования , которая реализует основные полезные конструкции, такие как REPEAT(times, x)
, IF(value, true, false)
, кортежи и т.д.
Большинство моих реализаций работают, перегружая макросы на основе их количества переменных аргументов или через счетчик:
// Example:
#define REPEAT_0(x)
#define REPEAT_1(x) x REPEAT_0(x)
#define REPEAT_2(x) x REPEAT_1(x)
#define REPEAT_3(x) x REPEAT_2(x)
// ...
// (these defines are generated using an external script)
// ...
#define REPEAT(count, x) CAT(REPEAT_, count)(x)
Это отлично работает, но я недавно встретил чрезвычайно интересную реализацию макрорекурсии Пола Фульца.
До раздела отложенное выражение я не мог понять его статью.
Однако у меня много проблем с пониманием использования DEFER
и OBSTRUCT
.
Paul реализует очень изящную версию REPEAT
, которая не требует script -generated, как это:
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
//An example of using this macro
#define M(i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7
DEFER
, OBSTRUCT
и другие утилиты реализованы как таковые:
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan
-
Когда препроцессор расширяет макрос, результат "окрашивается" до следующего сканирования - он не будет рекурсивно расширяться, если не произойдет дополнительное сканирование. Правильно ли это?
-
Увеличивает ли макрос
EXPAND(...)
дополнительное сканирование? Если это так, разрешает ли это сканирование макросы рекурсивно? Какая разница междуEXPAND(...)
иDEFER(id)
?- Увеличивает ли
DEFER
два дополнительных сканирования?
- Увеличивает ли
-
Как насчет макроса
OBSTRUCT(...)
? Усиливает ли два дополнительных сканирования? -
Теперь - почему
OBSTRUCT
требуется в рекурсивной реализацииREPEAT
? Почему быDEFER
илиEXPAND
работать здесь?