__VA_ARGS__ 在 BOOST_PP_SEQ_FOR_EACH 内部调用时看到多余的空 arg

__VA_ARGS__ sees extra empty arg when invoked inside BOOST_PP_SEQ_FOR_EACH

我的实际代码示例非常复杂,但我会尝试用一个简单的插图来总结我所看到的行为。

我有一个宏,我希望能够单独调用,或者作为更大的宏扩展的一部分多次调用:

#define DO_STUFF(name,...)   \
    STUFF1(name,__VA_ARGS__) \
    STUFF2(name,__VA_ARGS__) \
    STUFF3(name,__VA_ARGS__)

我可以直接在源文件中使用 DO_STUFF(dave, int, char) 和类似的变体,它会生成我期望的代码。

我还想用另一个输入列表调用 DO_STUFF 宏的大列表。为了处理这种情况,我使用带有元组序列(或可变序列)的升压预处理器:

DO_LOTS_OF_STUFF(
      (dave, ball, pen)          \
      (alice, cat, dog, bicycle) \
      (peter, bird) )

我对 DO_LOTS_OF_STUFF 的定义如下:

#define DO_LOTS_OF_STUFF(SEQ)       \
   BOOST_PP_SEQ_FOR_EACH(              \
     INVOKE_DS, _,                     \
     BOOST_PP_VARIADIC_SEQ_TO_SEQ(SEQ) \
   )

#define INVOKE_DS( r, data, elem )      \
   DO_STUFF(BOOST_PP_TUPLE_ENUM(elem)); \

当我调用 DO_LOTS_OF_STUFF 时,如上图所示,STUFF1STUFF2STUFF3 都在末尾用一个额外的逗号调用,参数为空。

如果我在调用 DO_STUFF 时中断扩展(通过更改其名称),预处理器输出看起来像我期望的那样:

DO_STUFF(dave, ball, pen)
DO_STUFF(alice, cat, dog, bicycle)
DO_STUFF(peter, bird)

如果我在 STUFF1STUFF2STUFF3 级别中断扩展,它们会出现在输出中并带有一个额外的空参数:

STUFF1(dave, ball, pen,)
STUFF2(dave, ball, pen,)
STUFF3(dave, ball, pen,)
STUFF1(alice, cat, dog, bicycle,)
STUFF2(alice, cat, dog, bicycle,)
STUFF3(alice, cat, dog, bicycle,)
STUFF1(peter, bird,)
STUFF2(peter, bird,)
STUFF3(peter, bird,)

这只是像 "don't use ##" 这样的预处理器元编程中要避免的事情之一吗? "Don't use __VA_ARGS__ in nested macros"?

关于如何定义 DO_STUFFDO_LOTS_OF_STUFF 以避免此问题的任何建议?

我明白是怎么回事了。

在我用 SEQ_FOR_EACH 调用 DO_STUFF 的地方我使用 BOOST_PP_TUPLE_ENUM:

#define INVOKE_DS( r, data, elem )      \
   DO_STUFF(BOOST_PP_TUPLE_ENUM(elem)); \

BOOST_PP_TUPLE_ENUM 将元组 (a,b,c,d) 转换为没有括号 a,b,c,d.

的逗号分隔标记

我假设那意味着 DO_STUFF(BOOST_PP_TUPLE_ENUM((a,b,c,d))) 会看到 4 个参数,但实际上它仍然只看到一个 a,b,c,d.

这个扩展:

#define DO_STUFF(name,...)   \
    STUFF1(name,__VA_ARGS__) \
    STUFF2(name,__VA_ARGS__) \
    STUFF3(name,__VA_ARGS__)

实际上是在这种情况下添加额外的空参数,因为 __VA_ARGS__ 是空的。

所以解决方案非常简单。我刚刚创建了 DO_STUFF 宏的不同变体,用于 DO_LOTS_OF_STUFF 案例

#define DO_LOTS_OF_STUFF(SEQ)       \
   BOOST_PP_SEQ_FOR_EACH(              \
     INVOKE_DS, _,                     \
     BOOST_PP_VARIADIC_SEQ_TO_SEQ(SEQ) \
   )

#define INVOKE_DS( r, data, elem )      \
   DO_STUFF_1(BOOST_PP_TUPLE_ENUM(elem)); \

#define DO_STUFF_1(tuple_args)   \
    STUFF1(tuple_args) \
    STUFF2(tuple_args) \
    STUFF3(tuple_args)