我最近遇到了类似的问题,并且我确实相信有解决方案。
关键思想是,有一种方法可以编写一个宏NUM_ARGS
来计算给定可变参数宏的参数数量。您可以使用NUM_ARGS
build 的变体NUM_ARGS_CEILING2
,它可以告诉您可变参数宏是被赋予1个参数还是2个或更多个参数。然后,你可以写你的Bar
,以便它使用宏NUM_ARGS_CEILING2
和CONCAT
其中一个期望的是1周的说法,而另一个预期的参数个数可变大于1:到它的参数发送给两个辅助宏之一。
这是我使用此技巧编写宏的示例,该宏UNIMPLEMENTED
非常类似于BAR
:
第1步:
/**
* A variadic macro which counts the number of arguments which it is
* passed. Or, more precisely, it counts the number of commas which it is
* passed, plus one.
*
* Danger: It can't count higher than 20. If it's given 0 arguments, then it
* will evaluate to 1, rather than to 0.
*/
#define NUM_ARGS(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, \
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define NUM_ARGS_COUNTER(a1, a2, a3, a4, a5, a6, a7, \
a8, a9, a10, a11, a12, a13, \
a14, a15, a16, a17, a18, a19, a20, \
N, ...) \
N
步骤1.5:
/*
* A variant of NUM_ARGS that evaluates to 1 if given 1 or 0 args, or
* evaluates to 2 if given more than 1 arg. Behavior is nasty and undefined if
* it's given more than 20 args.
*/
#define NUM_ARGS_CEIL2(...) \
NUM_ARGS_COUNTER(__VA_ARGS__, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 1)
第2步:
#define _UNIMPLEMENTED1(msg) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__)
#define _UNIMPLEMENTED2(msg, ...) \
log("My creator has forsaken me. %s:%s:%d." msg, __FILE__, \
__func__, __LINE__, __VA_ARGS__)
步骤3:
#define UNIMPLEMENTED(...) \
CONCAT(_UNIMPLEMENTED, NUM_ARGS_CEIL2(__VA_ARGS__))(__VA_ARGS__)
以常规方式实施CONCAT的位置。作为快速提示,如果以上内容令人困惑:CONCAT的目标是扩展到另一个宏“调用”。
请注意,未使用NUM_ARGS本身。我只是将其包括在内,以说明此处的基本技巧。请参阅Jens Gustedt的P99博客,以获取对它的很好处理。
两个注意事项:
NUM_ARGS处理的参数数量受到限制。我的最多只能处理20个,尽管这个数目完全是任意的。
如图所示,NUM_ARGS有一个陷阱,即当给定0个参数时它返回1。其要点是NUM_ARGS技术上是在计算[逗号+ 1],而不是args。在这种情况下,它实际上对我们有利。_UNIMPLEMENTED1可以很好地处理一个空令牌,这使我们不必编写_UNIMPLEMENTED0。Gustedt对此也有一个解决方法,尽管我没有使用它,而且我不确定它是否适合我们在此所做的工作。
BAR
而不是FOO
首先使用?