我将信息存储在这样的宏列表中:
#define MYLIST(XX) \
XX(1, hello) \
XX(2, world) \
...
现在,我想在同一“调用堆栈”中两次使用此宏。这是一个愚蠢的例子:
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
int foo = MYLIST(AA) 0;
int foo = 1 + (MYLIST(BB) 0) + 2 + (MYLIST(BB) 0) + 0;
是否可以使用MYLIST
现有列表在同一“调用堆栈”中使用两次(或解决方法)?
以下代码将起作用:
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
int foo = EVAL2(MYLIST(AA)) 0;
输出: int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
不幸的是,我对它为什么起作用没有深刻的了解。我只是尝试了一些技巧,在这种情况下往往会有所帮助。但是我可以解释一些。
有时宏被标记为“不再进一步扩展”。该标志通常在您开始扩展它时设置,并在扩展完成后取消设置。这倾向于防止递归。
当宏扩展为令牌时,这些令牌通常是类似于函数的宏调用,有时我们已经通过了将其扩展的阶段。
我们可以通过在评估时添加第二个宏来创建宏调用,从而将宏的扩展延迟到标志不会引起任何问题的程度,从而绕过第一个问题。就是DELAYED_CALL
那样 但是这样做时,我们遇到了第二个问题,因此我们必须添加一些调用以EVAL
使宏被重新扫描(总是扫描类似函数的宏的参数,因此将标记序列传递给函数-如宏,仅回显其参数将导致重新扫描)。
有时我们需要进行几次重新扫描才能使所有工作正常进行。EVAL2(X)
是的简写EVAL(EVAL(X))
。有时将需要更多评估。
下面的代码使事情更加清晰。请注意,MYLIST2版本如何需要少一个EVAL;这是因为AA调用了MYLIST,而MYLIST2是设置了违规标志的那个。
#define EVAL(...) __VA_ARGS__
#define EVAL2(...) EVAL(__VA_ARGS__)
#define EVAL3(...) EVAL2(__VA_ARGS__)
#define EMPTY()
#define DELAYED_CALL(F, ...) F EMPTY()(__VA_ARGS__)
#define BB(i,n) i +
#define AA(i,n) i + (MYLIST(BB) 0) +
#define MYLIST(XX) \
DELAYED_CALL(XX, 1, hello) \
DELAYED_CALL(XX, 2, world)
#define MYLIST2(XX) \
XX(1, hello) \
XX(2, world)
% MYLIST
int foo = MYLIST(AA) 0;
int foo = EVAL(MYLIST(AA)) 0;
int foo = EVAL2(MYLIST(AA)) 0;
% MYLIST2
int foo = MYLIST2(AA) 0;
int foo = EVAL(MYLIST2(AA)) 0;
int foo = EVAL2(MYLIST2(AA)) 0;
其输出将是:
% MYLIST
int foo = AA (1, hello) AA (2, world) 0;
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
% MYLIST2
int foo = 1 + (BB (1, hello) BB (2, world) 0) + 2 + (BB (1, hello) BB (2, world) 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
int foo = 1 + (1 + 2 + 0) + 2 + (1 + 2 + 0) + 0;
(百分号没什么特别的。我只是想将注释显示在输出中,并且在预处理期间将删除C样式的注释。)
进一步阅读。这篇文章的作者比我理解的要好得多。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句