我的实际代码示例非常复杂,但我将尝试通过简单的说明总结我所看到的行为。
我有一个宏,我希望能够单独调用,或者多次作为更大宏扩展的一部分调用:
#define DO_STUFF(name,...) \
STUFF1(name,__VA_ARGS__) \
STUFF2(name,__VA_ARGS__) \
STUFF3(name,__VA_ARGS__)
我可以直接在源文件中使用DO_STUFF(dave, int, char)
和类似的变体,它会生成我期望的代码。
我还想用另一个输入列表调用DO_STUFF
宏的大列表。为了处理这种情况,我使用带有一系列元组(或可变序列)的boost预处理器:
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
时,STUFF1
,STUFF2
和STUFF3
都会在末尾用额外的逗号调用,并带有空参数。
如果我在调用DO_STUFF
的位置(通过更改其名称)中断扩展,则预处理器输出看起来像我期望的那样:
DO_STUFF(dave, ball, pen)
DO_STUFF(alice, cat, dog, bicycle)
DO_STUFF(peter, bird)
如果我在STUFF1
,STUFF2
和STUFF3
级别中断展开,它们会在输出中显示一个额外的空参数:
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,)
这只是预处理器元编程中要避免的事情之一,例如“不要使用##
”吗? “不要在嵌套宏中使用__VA_ARGS__
”?
有关如何定义DO_STUFF
或DO_LOTS_OF_STUFF
以避免此问题的任何建议吗?
答案 0 :(得分:0)
我弄清楚发生了什么。
我使用DO_STUFF
调用SEQ_FOR_EACH
的地方我使用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
。{/ p>
此扩展:
#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)