如何定义一个 C 宏IFARGS(YES, NO, ...)
,使得IFARGS
不带附加参数的调用产生NO
,而IFARGS
用一个或多个参数调用产生YES
?
我有一个使用 GCC 的答案(见下文),但如果可能的话,我更喜欢 C99 的答案(或证明它不可能)。
如何定义一个 C 宏IFARGS(YES, NO, ...)
,使得IFARGS
不带附加参数的调用产生NO
,而IFARGS
用一个或多个参数调用产生YES
?
我有一个使用 GCC 的答案(见下文),但如果可能的话,我更喜欢 C99 的答案(或证明它不可能)。
在 C99 中,可以检测一个宏参数是否为空,但是要使其对可能出现在该参数中的所有可能性(参数本身正在扩展、包含()
和类似的东西)保持稳健是很困难的。我的宏包P99实现了这样的东西,所以你不必太担心。这样您的宏可以实现为
#define IFARGS(YES, NO, ...) P99_IF_EMPTY(__VA_ARGS__)(YES(__VA__ARGS__))(NO())
顾名思义,P99 仅基于 C99 功能构建。
#define GET(_0, _1) _0 // Return the first of two arguments
#define GET_(_0, _1) _1 // Return the second of two arguments
#define JOIN(_0, _1) _0 ## _1 // Concatenate two arguments
#define EJOIN(_0, _1) JOIN(_0, _1) // Expand macros and concatenate
#define FIRST(_, ...) _ // Truncate everything after first comma
#define EFIRST(_) FIRST(_) // Expand argument and pass to FIRST
#define REST(_0, ...) __VA_ARGS__ // Remove everything before first comma
#define GET_GET(...) \
EJOIN(GET, EFIRST(REST(,,##__VA_ARGS__ _))) // Branch between GET and GET_
#define IFARGS(YES, NO, ...) GET_GET(__VA_ARGS__)(YES, NO)
请注意,如果这在 C99 中是可能的,那么就可以模拟##__VA_ARGS__
,如下所示:
#define PREPEND_COMMA(...) , __VA_ARGS__
#define NO_COMMA()
#define PREPEND_COMMA_IF_NONEMPTY(...) IFARGS(PREPEND_COMMA, NO_COMMA, __VA_ARGS__)(__VA_ARGS__)
然后任何实例, ##__VA_ARGS__
都可以替换为PREPEND_COMMA_IF_NONEMPTY(__VA_ARGS__)
.