我想制作一个带有可变数量参数的宏F
,该宏扩展为每个由||
分隔的参数。例如F(a, b, c)
应该扩展为a || b || c
,F(a)
应该扩展为a
,依此类推。
我知道C不支持递归宏。我目前最多只需要4个参数就可以了。
我在想类似#define F(a, ...) a || F(__VA_ARGS__)
的东西,然后在想第二个宏使它扩展4倍,但是我完全不确定其他宏应该是什么样子。而且我有时遇到__VA_ARGS__
为空的问题。任何其他想法将不胜感激。
限制:必须与任何符合标准的C99编译器一起使用。
编辑:我已经使用Overloading Macro on Number of Arguments进行了此操作,但是仍然想知道是否还有其他解决方案。
答案 0 :(得分:4)
基础非常简单:
#define COUNT(...) COUNT_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_(A0, A1, A2, A3, A4, A5, A6, A7, ...) A7
#define F0()
#define F1(A0) A0
#define F2(A0, A1) A0 || A1
#define F3(A0, A1, A2) F2(A0, A1) || A2
#define F4(A0, A1, A2, A3) F3(A0, A1, A2) || A3
#define F(...) C(F, COUNT(__VA_ARGS__))(__VA_ARGS__)
#define C(X, Y) C_(X, Y)
#define C_(X, Y) X ## Y
其中C
是通常的两步串联宏。不过,还有一个问题:空的__VA_ARGS__
。
实际上,C标准本身不支持此功能(您必须切换到即将推出的C ++ 20才能实现–或C20反向移植?)。而且任务非常繁重(按原样,COUNT()
的结果为1,其中COUNT_
宏中的第一个参数为空!)。我很早以前就设法解决了类似的任务,因此您可能想看看there,应该很容易将相关部分导入到这里...
答案 1 :(得分:0)
这有点重,但是如果您可以使用库,那么Boost.PP可以为您完成很多繁重的工作。它同时支持C和C ++,并且是仅标头的库(显然)。您的用例将如下所示:
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
#define OP(s, state, x) state || x
#define F(...) BOOST_PP_SEQ_FOLD_LEFT(OP, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
上面的方法将可变参数转换为增强PP序列,然后通过应用OP
对其进行折叠。 state
是每个“迭代”的中间结果。它的初始“值”为0(因此结果表达式不依赖于它)。
当运行F(1, 2, 3)
through gcc -E
时,我们得到:
0 || 1 || 2 || 3
主要注意事项是参数列表为空(正式GCC扩展名,无效的C99)是它将扩展为0 ||
。因此,值得牢记。可以使用参数计数(使用Boost.PP)在两个实现之一中进行选择,具体取决于0或多个arg来解决问题。