组合不同的 arity X-macros

Combine different arity X-macros

我正在为编程语言定义词法分析器。其中一部分涉及 table 个关键字和标记:

#define FOREACH_KEYWORD(V)                                                     \
  V(And, and)                                                                  \
  V(Else, else)                                                                \
  V(False, false)                                                              \
  V(If, if)                                                                    \
  V(Or, or)                                                                    \
  V(True, true)

#define FOREACH_TOKEN(V)                                                       \
  V(Plus)                                                                      \
  V(Minus)                                                                     \
  V(Times)                                                                     \
  V(Div)                                                                       \
  FOREACH_KEYWORD(V)

这些宏的用途如下:

const char *kTokenTypeNames[] = {
#define STR(NAME) #NAME,
  FOREACH_TOKEN(STR)
#undef STR
};

// which would ideally expand to

const char *kTokenTypeNames[] = {
 "Plus", "Minus", "Times", "Div", "And", "Else", "False", "If", "Or", "True",
};

并且关键字应该包含在标记列表中。上面的伪代码不起作用,因为两个不同的 V 宏参数具有不同的参数。我希望任何必须处理标记的宏只需要采用 1 个参数,而任何处理关键字的宏需要采用 2 个参数。我不想让所有内容都可变。我觉得应该可以添加一些插页式宏来使这种组合成为可能,但我还没有足够聪明地做到这一点。

我想,总的来说:我希望能够采用一个数量为 N 的 X 宏并将其减少到某个 M,其中 M 小于 N。

我怎样才能做到这一点?

当一个列表包含另一个时,我不确定您为什么认为这两个列表应该是两个而不是一个。要么列出一个列表,要么列出两个单独的列表。

如果您创建两个单独的列表并删除 FOREACH_TOKEN 列表中的 FOREACH_KEYWORD(V),那么您可以简单地进行两个单独的宏调用:

const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
  FOREACH_TOKEN1(STR1)
  FOREACH_KEYWORD(STR2)
};

根据您的规格,我想这就是您要找的。

#define AB_TO_A(A,B) (A)
#define EVAL(...) __VA_ARGS__

#define FOREACH_KEYWORD(V) \
  V(And, and)     \
  V(Else, else)   \
  V(False, false) \
  V(If, if)       \
  V(Or, or)       \
  V(True, true)

#define FOREACH_TOKEN(V) \
  V(Plus)   \
  V(Minus)  \
  V(Times)  \
  V(Div)    \
  EVAL(FOREACH_KEYWORD(V AB_TO_A))

const char *kTokenTypeNames[] = {
#define STR(NAME) #NAME,
  FOREACH_TOKEN(STR)
#undef STR
};

Coliru 演示 here.