__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
时,如上图所示,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,)
这只是像 "don't use ##
" 这样的预处理器元编程中要避免的事情之一吗? "Don't use __VA_ARGS__
in nested macros"?
关于如何定义 DO_STUFF
或 DO_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)
我的实际代码示例非常复杂,但我会尝试用一个简单的插图来总结我所看到的行为。
我有一个宏,我希望能够单独调用,或者作为更大的宏扩展的一部分多次调用:
#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
时,如上图所示,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,)
这只是像 "don't use ##
" 这样的预处理器元编程中要避免的事情之一吗? "Don't use __VA_ARGS__
in nested macros"?
关于如何定义 DO_STUFF
或 DO_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)