可变参数宏,其输出参数以“ ||”分隔

时间:2018-12-31 04:39:47

标签: c c-preprocessor variadic-macros

我想制作一个带有可变数量参数的宏F,该宏扩展为每个由||分隔的参数。例如F(a, b, c)应该扩展为a || b || cF(a)应该扩展为a,依此类推。

我知道C不支持递归宏。我目前最多只需要4个参数就可以了。

我在想类似#define F(a, ...) a || F(__VA_ARGS__)的东西,然后在想第二个宏使它扩展4倍,但是我完全不确定其他宏应该是什么样子。而且我有时遇到__VA_ARGS__为空的问题。任何其他想法将不胜感激。

限制:必须与任何符合标准的C99编译器一起使用。

编辑:我已经使用Overloading Macro on Number of Arguments进行了此操作,但是仍然想知道是否还有其他解决方案。

2 个答案:

答案 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来解决问题。