如何在同一“调用堆栈”中两次使用宏列表?

朱利叶斯

我将信息存储在这样的宏列表中:

#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;

但是,此操作不起作用,因为MYLIST 它不会第二次扩展

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在WHERE子句中两次使用同一列表?

如何在同一页面中两次使用 JQuery 函数?

如何在同一个选择中两次使用函数结果

如何在其他课程中使用super()两次调用同一课程?

如何在不递归的情况下两次调用同一函数

如何在Keras的一个模型中两次使用同一层/模型?

如何在CAFFE的新网络中重复使用同一网络两次

如何在同一网页中两次使用相同的JavaScript小部件?

如何在SQL中使用同一列两次获取唯一ID

在Java中对流使用同一列表两次

如何在IntelliJ中两次运行同一应用程序?

如何在mysql中两次在1个表中选择同一列

如何在Java中两次读取同一文件?

如何在同一文件中两次运行awk

如何在SQL中按同一列两次过滤?

如何在同一线程上使用相同的互斥锁两次?

如何在同一对象上使用* ngFor迭代两次?

如何在同一页面上两次使用相同的jquery脚本

在同一活动中两次使用接口

React:如何在同一页面中两次使用相同的组件,但只为一次加载一个脚本标签

如何在 for 循环中使用多处理并行化对同一个函数的两次调用,并使用不同的参数?

如何在EF Core中两次调用ThenInclude?

如何在Python中的列表上循环两次

如何在同一SQL语句中使用两个条件对字段进行两次求和

如何在 ReactJS 中制作可重用的下拉过滤器,它是 DRY 并且可以在同一组件中使用两次

使用group by查询同一张表中的同一列两次

页面两次调用同一功能的JSF

两次调用同一函数-JavaScript

如何在Java脚本或jquery中单击同一按钮两次时计算间隔时间