3

考虑以下用户样式的x-macro

#define PRIMES_X(func) \
  func(2) \
  func(3) \
  func(5)

func我们可以使用它用前三个素数重复调用传入的宏。例如:

#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)

将声明返回 void 的函数foo2(),foo3()foo5().

到目前为止,一切都很好。现在假设我想在 x-macro 本身的定义中使用一个宏作为参数,如下所示:

#define MAX_PRIME 5
#define PRIMES_X(func) \
  func(2) \
  func(3) \
  func(MAX_PRIME)

它不起作用,因为MAKE_FUNC现在将尝试声明void fooMAX_PRIME(),因为(我想)令牌连接发生而不扩展MAX_PRIME

我可以解决这个问题,让它foo5()像以前一样声明吗?

4

2 回答 2

2

您可以插入另一个级别的宏扩展(PRIMES_X2如下)。

#define MAKE_FUNC(num) void foo ## num();
#define MAX_PRIME 5
#define PRIMES_X(func) PRIMES_X2(func, MAX_PRIME)
#define PRIMES_X2(func, maxPrimePar) \
  func(2) \
  func(3) \
  func(maxPrimePar)

PRIMES_X(MAKE_FUNC)

输出gcc -E

void foo2(); void foo3(); void foo5();
于 2018-05-18T05:28:39.087 回答
1

Yunnosch 的回答很好,但是要进一步旋转 X 宏的疯狂,您也可以使用列表内的宏调用来执行此操作,而不是在列表外使用包装器宏。这样做的好处是您可以将列表中的“变量”传递给被调用的宏。

我想这可能有一些用处 - 例如,假设您希望使用 X 宏来声明不同类型的函数?

例子:

#define MAX_PRIME 5

#define CREATE_FUNC(func, ret_type, param) func(ret_type, param)

#define PRIMES_X(func)                 \
  CREATE_FUNC(func, int,    2)         \
  CREATE_FUNC(func, void,   3)         \
  CREATE_FUNC(func, double, MAX_PRIME) \

#define MAKE_FUNC(ret_type, num) ret_type foo ## num(void);
  PRIMES_X(MAKE_FUNC)
#undef MAKE_FUNC

调试代码以检查函数是否确实获得了预期的原型:

int main(void)
{
  (void)foo2();
  foo3();
  (void)foo5();
}

int foo2 (void){ return 0;}
void foo3 (void){}
double foo5 (void){ return 0.0;}
于 2018-05-18T07:04:01.213 回答