我最近遇到了类似的问题,我相信有一个解决方案。
关键思想是有一种方法可以编写一个宏NUM_ARGS
来计算给定可变参数宏的参数数量。您可以使用NUM_ARGS
to 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 在技术上计数 [commas + 1],而不是 args。在这种特殊情况下,它实际上对我们有利。_UNIMPLEMENTED1 可以很好地处理空令牌,它使我们不必编写 _UNIMPLEMENTED0。Gustedt 也有一个解决方法,虽然我没有使用它,我不确定它是否适用于我们在这里所做的事情。