我想知道如何将一元函数(或另一个宏)应用于宏的可变参数,例如
int f(int a);
#define apply(args...) <the magic>
apply(a, b, c)
Run Code Online (Sandbox Code Playgroud)
展开
f(a)
f(b)
f(c)
Run Code Online (Sandbox Code Playgroud)
请注意,参数的数量未知。
下面的代码可以满足您所要求的最多 1024 个参数,并且无需使用 boost 等其他内容。它定义了一个EVAL(...)宏MAP(m, first, ...)来执行递归,并在每次迭代时使用m带有下一个参数的宏first。
使用它,你的apply(...)看起来像:#define apply(...) EVAL(MAP(apply_, __VA_ARGS__))。
它主要是从C Pre-Processor Magic复制而来。那里的解释也很好。EVAL(...)您还可以像在这个git 存储库中一样下载这些帮助器宏一样下载这些帮助器宏,实际代码中也有很多解释。它是可变的,因此它需要您想要的参数数量。
但我更改了FIRST和SECOND宏,因为它使用 Gnu 扩展,就像我从中复制的源中一样。@HWalters在下面的评论中说道:
具体来说,6.10.3p4:“否则[标识符列表以...结尾]调用中的参数应多于宏定义中的参数(不包括...)”。
主要功能部分:
int main()
{
int a, b, c;
apply(a, b, c) /* Expands to: f(a); f(b); f(c); */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
宏定义:
#define FIRST_(a, ...) a
#define SECOND_(a, b, ...) b
#define FIRST(...) FIRST_(__VA_ARGS__,)
#define SECOND(...) SECOND_(__VA_ARGS__,)
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a,b) a ## b
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define apply_(x) f(x);
#define apply(...) EVAL(MAP(apply_, __VA_ARGS__))
Run Code Online (Sandbox Code Playgroud)
要测试宏扩展,使用 gcc 和命令行参数很有用-E:
$ gcc -E srcFile.c
Run Code Online (Sandbox Code Playgroud)
因为您会收到具体的错误消息并了解发生了什么。