C 从现有x宏创建相关x宏

C 从现有x宏创建相关x宏,c,c-preprocessor,x-macros,C,C Preprocessor,X Macros,考虑以下用户样式: 我们可以使用它来用前四个素数重复展开传入的宏func。例如: #define MAKE_FUNC(num) void foo ## num(); PRIMES_X(MAKE_FUNC) 将声明无效的返回函数foo2(),foo3(),foo5()和foo7() 到目前为止,一切顺利 假设我想创建一个相关的x-宏,它不使用裸素数2,3。。。但是使用从它派生的一些标记,例如上面的函数名。就是我要这个, #define PRIMES_FOO_X(func) \ func(fo

考虑以下用户样式:

我们可以使用它来用前四个素数重复展开传入的宏
func
。例如:

#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)
将声明无效的返回函数
foo2()
foo3()
foo5()
foo7()

到目前为止,一切顺利

假设我想创建一个相关的x-宏,它不使用裸素数
2
3
。。。但是使用从它派生的一些标记,例如上面的函数名。就是我要这个,

#define PRIMES_FOO_X(func) \
  func(foo2) \
  func(foo3) \
  func(foo5) \
  func(foo7) 
但是如果不把它全部写出来(事实上,它会在
PRIMES\ux
改变的那一刻失去同步)

我想要的是一种用
PRIMES\u FOO\u X
来定义
PRIMES\u FOO\u X的方法。我几乎可以做到这一点,例如:

#define FOO_ADAPT(num) func(foo ## num)
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT)
在这种情况下,
PRIMES\u FOO\u X
扩展为:

  func(foo2) \
  func(foo3) \
  func(foo5) \
  func(foo7)
…看起来不错,但是这里的
func
不是传递的参数,而是普通的标记
func
,因为
FOO\u ADAPT
没有名为
func
的参数,只有
PRIMES\u FOO\u X(func)
有(并且没有使用它)


我想不出一个办法来解决这个问题。

也许一个简单的解决办法就足够了

您可以事先声明参数,而不是将参数
func
传递给
PRIMES\u FOO\u X
。例如,在此代码中,我们使用
FOO\u func
来保存
func

#define PRIMES_FOO_X PRIMES_X(FOO_ADAPT)
#define FOO_ADAPT(num) FOO_FUNC(foo ## num)

#define FOO_FUNC bar
PRIMES_FOO_X

#undef  FOO_FUNC
#define FOO_FUNC(x) x();
PRIMES_FOO_X
结果是:

bar(foo2) bar(foo3) bar(foo5) bar(foo7)

foo2(); foo3(); foo5(); foo7();

一个关键的观察结果……鉴于此:

#define PRIMES_X(func) \
  func(2) \
  func(3) \
  func(5) \
  func(7)
PRIMES_X()
扩展为
(2)(3)(5)(7)
,就CPP元编程而言,它是一种序列数据结构。记住,让我们开始向后走。您想要这样的东西:

#define PRIMES_FOO_X(func) \
  /* something that expands to: func(foo2) func(foo3) func(foo5) func(foo7) */
#define PRIMES_FOO_X(func) \
  /* something that expands to: \
   * func(FOOIDENT_OF(2)) func(FOOIDENT_OF(3)) \
   * func(FOOIDENT_OF(5)) func(FOOIDENT_OF(7)) */
…您希望
foo2
foo3
foo5
foo7
来自
PRIMES\ux
扩展。显然,然后
2
变成
foo2
3
变成
foo3
,等等;所以让我们假设这样的情况发生在
FOOIDENT\code>宏中de>PRIMES_FOO_X
您需要调用
(FOOIDENT_OF(2))
上的
func
,等等;也就是说,您需要更精确地如下所示:

#define PRIMES_FOO_X(func) \
  /* something that expands to: func(foo2) func(foo3) func(foo5) func(foo7) */
#define PRIMES_FOO_X(func) \
  /* something that expands to: \
   * func(FOOIDENT_OF(2)) func(FOOIDENT_OF(3)) \
   * func(FOOIDENT_OF(5)) func(FOOIDENT_OF(7)) */
结合这两个理念,我们拥有的要素是:

  • func
    ,在派生X宏中应用的操作
  • FOOIDENT_OF
    ,将每个X宏参数列表转换为新形式的操作
  • PRIMES_X()
    ,所有参数列表的序列
这是可能的,如果我们使用boost预处理器的序列,甚至有点容易做到

#include <boost/preprocessor/seq.hpp>

#define PAIR_ELEMENT_1(A,B) A
#define PAIR_ELEMENT_2(A,B) B

#define PAIR_XFORM_MACRO(r, data, elem) \
   PAIR_ELEMENT_1 data ( PAIR_ELEMENT_2 data (elem) )

#define PAIR_XFORM(PAIR_, SEQ_) \
   BOOST_PP_SEQ_FOR_EACH(PAIR_XFORM_MACRO, PAIR_, SEQ_)

是堆叠弯曲上的外观。

请尝试以下解决方案:

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

#define DERIVE_TOKEN(num) (foo##num);
#define FOO_ADAPT(f) f DERIVE_TOKEN
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT(f))
// 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)
它膨胀了

PRIMES_FOO_X(funct)

(注:这是我第二次回答这个问题)

受H Walters使用Boost的启发,我想找到一个C-only解决方案。William Swanson对的出色回答似乎提供了一个解决方案

从他的答案中提取代码,我们可以生成以下解决方案:

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

#define DERIVE_TOKEN(num) (foo##num);
#define FOO_ADAPT(f) f DERIVE_TOKEN
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT(f))
// 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();
注:

  • MAP
    的定义中,我必须删除
    后面的逗号,以防止在末尾出现额外的垃圾值。但这会破坏宏的其他用途。人们可能会认为在
    FOO\u列表中移动逗号可以解决此问题,但事实并非如此。(Todo:fix)

  • 任何使用
    ##
    串联运算符的MAP-like或FOREACH-like解决方案都不太可能在这里工作,因为宏给出的任何输入列表都不会展开。(这对我来说是新的:()


编辑:第二个使用相同想法的替代解决方案基于的代码。输出与上述相同。(这表明我对
#
的评论不正确。)


如果您能给出一两个用例来显示
PRIMES\u FOO\u X
宏所需的输出,这可能会有所帮助。@JosephQuinsey那么
PRIMES\u FOO\u X
的所需
PRIMES\u FOO\u X
扩展在我的问题的末尾显示出来:它的行为应该与
定义PRIMES\u FOO\u X(func)完全一样`后面是我最后一个代码块中显示的文本。当然,我不想手工写出它,但它要有这种效果,但要基于现有的
PRIMES\ux`宏(因此,对
PRIMES\ux
的特定更改将反映在
PRIMES\ufoo\ux
中)。