首先在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_()
延迟宏展开这样的是递归可在预处理器实现的途径之一。
和宏一般都是邪恶的 – Drakosha
Drakosha:我会不同意。了解他们和他们的陷阱,他们可以成为一个方便的工具。 – orlp
nightcracker:当然,你需要学习它们,但你应该尽量避免使用它们,除非它是最后一个选项(并且我upvoted你的答案) – Drakosha