从现有的 x 宏创建相关的 x 宏
Creating a related x-macro from an existing one
考虑以下用户风格 x-macro:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
我们可以用它来扩展传入的宏 func
重复使用前四个素数。例如:
#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)
将声明返回 void 的函数 foo2()
、foo3()
、foo5()
和 foo7()
.
到目前为止,还不错。
假设我知道想要创建一个相关的 x-macro,它调用它的参数不是使用裸素数 2
、3
,...而是使用从它派生的一些标记,比如上面的函数名。也就是说,我想要这个:
#define PRIMES_FOO_X(func) \
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
但实际上并没有全部写出来(实际上,PRIMES_X
更改时它会不同步。
我想要的是根据 PRIMES_X
定义 PRIMES_FOO_X
的方法。我几乎可以到达那里,例如:
#define FOO_ADAPT(num) func(foo ## num)
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT)
在这种情况下,PRIMES_FOO_X
扩展为:
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
... 看起来是正确的,但是这里的 func
不是传递的参数,而是普通标记 func
因为 FOO_ADAPT
没有名为 func
,只有 PRIMES_FOO_X(func)
可以(而且它不使用它)。
我想不出一个方法来完成这项工作。
也许头脑简单的解决方法就足够了。
您可以预先声明它,而不是将参数 func
传递给 PRIMES_FOO_X
。例如,在这段代码中我们使用 FOO_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 元编程而言,它是一个 sequence 数据结构。记住这一点,让我们开始倒退。你想要这样的东西:
#define PRIMES_FOO_X(func) \
/* something that expands to: func(foo2) func(foo3) func(foo5) func(foo7) */
...并且您希望 foo2
、foo3
、foo5
、foo7
来自 PRIMES_X
扩展。显然 2
变成 foo2
,3
变成 foo3
,等等;所以让我们假设这种变化是根据一个叫做 FOOIDENT_OF
的宏发生的。然后在 PRIMES_FOO_X
中你需要在 (FOOIDENT_OF(2))
上调用 func
,等等;也就是说,您想要更精确的东西:
#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_)
这里我有一个 PAIR_XFORM
,它接受一个 2 元组 ("pair") 的宏,并将它们都应用于序列的每个元素。 IOW,PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
生成我们的目标。现在我们需要的是生成新的 X-macro 并制作内部转换宏:
#define FOOIDENT_OF(N) foo##N
#define PRIMES_FOO_X(func) PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
Here是叠歪的样子
尝试以下解决方案:
#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))
扩展
PRIMES_FOO_X(funct)
到
funct (foo2); funct (foo3); funct (foo5); funct (foo7);
(备注:这是我第二次回答这个问题)
受 H Walters 的启发 using Boost, I wanted to find a C-only solution. William Swanson's excellent answer to Foreach macro on macros arguments 似乎提供了一个。
从他的回答中提取代码,我们可以生成这个解决方案:
// The first part here is taken from William Swanson's answer
// to
#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
的定义中,我不得不删除__VA_ARGS__
后面的逗号,以防止在末尾出现额外的垃圾值。但这会破坏其他用途的宏。有人会认为只需移动 FOO_LIST
中的逗号即可解决此问题,但事实并非如此。 (待办事项:修复)
任何使用 ##
连接运算符的类似 MAP 或类似 FOREACH 的解决方案都不太可能在这里工作,因为宏给出的任何输入列表 不是 展开。 (这对我来说是新的:()
编辑: 使用相同想法的第二种替代解决方案基于 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)
考虑以下用户风格 x-macro:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
我们可以用它来扩展传入的宏 func
重复使用前四个素数。例如:
#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)
将声明返回 void 的函数 foo2()
、foo3()
、foo5()
和 foo7()
.
到目前为止,还不错。
假设我知道想要创建一个相关的 x-macro,它调用它的参数不是使用裸素数 2
、3
,...而是使用从它派生的一些标记,比如上面的函数名。也就是说,我想要这个:
#define PRIMES_FOO_X(func) \
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
但实际上并没有全部写出来(实际上,PRIMES_X
更改时它会不同步。
我想要的是根据 PRIMES_X
定义 PRIMES_FOO_X
的方法。我几乎可以到达那里,例如:
#define FOO_ADAPT(num) func(foo ## num)
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT)
在这种情况下,PRIMES_FOO_X
扩展为:
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
... 看起来是正确的,但是这里的 func
不是传递的参数,而是普通标记 func
因为 FOO_ADAPT
没有名为 func
,只有 PRIMES_FOO_X(func)
可以(而且它不使用它)。
我想不出一个方法来完成这项工作。
也许头脑简单的解决方法就足够了。
您可以预先声明它,而不是将参数 func
传递给 PRIMES_FOO_X
。例如,在这段代码中我们使用 FOO_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 元编程而言,它是一个 sequence 数据结构。记住这一点,让我们开始倒退。你想要这样的东西:
#define PRIMES_FOO_X(func) \
/* something that expands to: func(foo2) func(foo3) func(foo5) func(foo7) */
...并且您希望 foo2
、foo3
、foo5
、foo7
来自 PRIMES_X
扩展。显然 2
变成 foo2
,3
变成 foo3
,等等;所以让我们假设这种变化是根据一个叫做 FOOIDENT_OF
的宏发生的。然后在 PRIMES_FOO_X
中你需要在 (FOOIDENT_OF(2))
上调用 func
,等等;也就是说,您想要更精确的东西:
#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_)
这里我有一个 PAIR_XFORM
,它接受一个 2 元组 ("pair") 的宏,并将它们都应用于序列的每个元素。 IOW,PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
生成我们的目标。现在我们需要的是生成新的 X-macro 并制作内部转换宏:
#define FOOIDENT_OF(N) foo##N
#define PRIMES_FOO_X(func) PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
Here是叠歪的样子
尝试以下解决方案:
#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))
扩展
PRIMES_FOO_X(funct)
到
funct (foo2); funct (foo3); funct (foo5); funct (foo7);
(备注:这是我第二次回答这个问题)
受 H Walters 的启发
从他的回答中提取代码,我们可以生成这个解决方案:
// The first part here is taken from William Swanson's answer
// to
#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
的定义中,我不得不删除__VA_ARGS__
后面的逗号,以防止在末尾出现额外的垃圾值。但这会破坏其他用途的宏。有人会认为只需移动FOO_LIST
中的逗号即可解决此问题,但事实并非如此。 (待办事项:修复)任何使用
##
连接运算符的类似 MAP 或类似 FOREACH 的解决方案都不太可能在这里工作,因为宏给出的任何输入列表 不是 展开。 (这对我来说是新的:()
编辑: 使用相同想法的第二种替代解决方案基于 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)