(备注:这是我对这个问题的第二个回答)
受到 H Walters 使用 Boost 的回答的启发,我想找到一个仅限 C 的解决方案。威廉斯旺森对宏参数的 Foreach 宏的出色回答似乎提供了一个。
从他的回答中获取代码,我们可以生成这个解决方案:
// The first part here is taken from William Swanson's answer
// to https://stackoverflow.com/questions/6707148
#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define MAP_OUT
#define MAP_END(...)
#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(item, next, ...) next MAP_OUT
#define MAP_NEXT1(item, next) MAP_NEXT0(item, next, 0)
#define MAP_NEXT(item, next) MAP_NEXT1(MAP_GET_END item, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__ (), 0))
// This is the example given by the OP:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
#define FOO_LIST(num) foo ## num, // note comma
#define PRIMES_FOO_X(f) MAP(f, PRIMES_X(FOO_LIST))
#define XXX(x) bar(x)
#define YYY(x) x();
PRIMES_FOO_X(XXX)
PRIMES_FOO_X(YYY)
结果,使用gcc -E -P ...
,是:
bar(foo2) bar(foo3) bar(foo5) bar(foo7)
foo2(); foo3(); foo5(); foo7();
笔记:
编辑:使用相同想法的第二种替代解决方案基于来自https://esolangs.org/wiki/ELIP的代码。输出与上述相同。(这表明我的评论##
不正确。)
// The first part here is based on esolangs.org/wiki/ELIP (CC0 public domain)
// (Note MAP here is their FOREACH)
#define XCAT(x,y) x ## y
#define CAT(x,y) XCAT(x,y)
#define EMPTY()
#define LPAREN (
#define RPAREN )
#define DEFER(x) x EMPTY()
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define TRUE(x,...) x
#define FALSE(x,...) __VA_ARGS__
#define TRANSFORM(seq, ...) CAT(TRANSFORM1_A seq,0END)(EAT, __VA_ARGS__)
#define TRANSFORM1_A(...) (EXPAND, __VA_ARGS__)() TRANSFORM1_B
#define TRANSFORM1_B(...) (EXPAND, __VA_ARGS__)() TRANSFORM1_A
#define TRANSFORM1_A0END
#define TRANSFORM1_B0END
#define RPXFRM(m, ...) m(RPAREN RPXFRM_ID)
#define RPXFRM_ID() RPXFRM
#define INFUSE(seq, ...) INFUSE5(INFUSE1(TRANSFORM(seq), __VA_ARGS__))
#define INFUSE1(xfrm, ...) INFUSE2 xfrm, __VA_ARGS__ RPXFRM xfrm
#define INFUSE2(m, ...) m(INFUSE3 DEFER(XCAT)(LPA,REN)(__VA_ARGS__), INFUSE2_ID)
#define INFUSE2_ID() INFUSE2
#define INFUSE3(...) INFUSE4(__VA_ARGS__)
#define INFUSE4(x, rest, ...) (__VA_ARGS__, EXPAND x)() rest, __VA_ARGS__
#define INFUSE5(...) INFUSE6(__VA_ARGS__)
#define INFUSE6(...) INFUSE7(__VA_ARGS__)
#define INFUSE7(seq, ...) seq
#define MAP(macro, seq) EXPAND(MAP1 INFUSE(seq, TRUE, macro)(FALSE, EAT,))
#define MAP1(p, m, ...) m(__VA_ARGS__) p(MAP1_ID)
#define MAP1_ID() MAP1
// This is the example given by the OP:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
#define FOO_LIST(num) (foo ## num) // parentheses, no commas
#define PRIMES_FOO_X(f) MAP(f, PRIMES_X(FOO_LIST))
#define XXX(x) bar(x)
#define YYY(x) x();
PRIMES_FOO_X(XXX)
PRIMES_FOO_X(YYY)