我想根据宏调用是否带参数来调用两个不同的宏。基于SO上有关特定参数数量的许多示例,我想出了这个,但它并没有扩展
__VA_OPT__(_WITH_ARGS)
:
#define FUN() "call without arguments"
#define FUN_WITH_ARGS(...) "call with arguments"
#define GET_MACRO(b) FUN##b
#define CALL(...) GET_MACRO(__VA_OPT__(_WITH_ARGS))(__VA_ARGS__)
CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"
如何扩展
__VA_OPT__(_WITH_ARGS)
以便 CALL
调用 FUN
或 FUN_WITH_ARGS
?
编辑:修复了拼写错误 - 仍然无法在 MSVC 中工作。
我对MSVC一无所知。
检测宏中零参数的常用方法是阅读 Jens Gustedt 的精彩博客 https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ ,复制他的代码并记住给予他信任。使用
ISEMPTY
宏,您可以根据扩展连接您的重载。
#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
#define ISEMPTY(...) \
_ISEMPTY( \
/* test if there is just one argument, eventually an empty \
one */ \
HAS_COMMA(__VA_ARGS__), \
/* test if _TRIGGER_PARENTHESIS_ together with the argument \
adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
/* test if the argument together with a parenthesis \
adds a comma */ \
HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
/* test if placing it between _TRIGGER_PARENTHESIS_ and the \
parenthesis adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
)
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _ISEMPTY(_0, _1, _2, _3) HAS_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,
#define CONCAT(a, b) a##b
#define XCONCAT(a, b) CONCAT(a, b)
#define FUN_1() "call without arguments"
#define FUN_0(...) "call with arguments"
#define CALL(...) XCONCAT(FUN_, ISEMPTY(__VA_ARGS__))(__VA_ARGS__)
CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"
但是人们只是在
参数数量上的重载宏中介绍的“通常”宏重载中使用
##__VA_ARGS__
。在较新的 C 预处理器中,我们可以使用 __VA_OPT__
代替 GNU 扩展。我使用的常用样式如下所示:
#define FUN_0() "call without arguments"
#define FUN_1(...) "call with arguments"
#define CALL_N(_4,_3,_2,_1,N,...) FUN_##N
#define CALL(...) CALL_N(_0 __VA_OPT__(,) __VA_ARGS__,1,1,1,0)(__VA_ARGS__)
CALL() // --> "call without arguments"
CALL(5) // --> "call with arguments"