Сначала есть различия между N_ X
и N_X
.Первые два жетона.Чтобы сформировать один токен, вы должны использовать оператор вставки токена ##
, но этот оператор запрещает расширение макроса, поэтому:
M(a) ## X //Compiler error can't paste ')' and X
Вызывает ошибку компиляции, потому что он пытается вставить M(a)
, а неN_
.Вы можете разрешить расширение макросов перед вставкой, используя дополнительный уровень макросов (это действительно часто используемый макрос):
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)
Однако в вашем случае это все равно не будет работать:
CAT(M(a), X) //expands to 0
Это потому, что вы используете объектные макросы, а не функциональные макросы.Если вы измените его на функциональные макросы, он будет работать так, как вы хотите:
#define N_() 0
#define N_X() 1
#define M(a) N_
CAT(M(arg), X)() // expands to 1
M(arg)() // expands to 0
Функциональные макросы более мощные, и вы можете отложить их расширение.Вот как вы можете отложить их для одного сканирования:
#define EMPTY()
#define DEFER(x) x EMPTY()
N_() //Expands to 0
DEFER(N_)() //Expands N_ ()
Задержка раскрытия макроса, как это, является одним из способов реализации рекурсии в препроцессоре.