为什么序列迭代在 C 宏中有效?
Why does sequence iteration work in C macro?
在编写C宏时,有一个技巧叫做"序列迭代"。它看起来像下面:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define FUNCTION(name) void name();
#define FUNCTION_TABLE(seq) CAT(FUNCTION_TABLE_1 seq, _END)
#define FUNCTION_TABLE_1(x) FUNCTION(x) FUNCTION_TABLE_2
#define FUNCTION_TABLE_2(x) FUNCTION(x) FUNCTION_TABLE_1
#define FUNCTION_TABLE_1_END
#define FUNCTION_TABLE_2_END
FUNCTION_TABLE((x) (y) (z) (e))
序列,即FUCTION_TABLE的参数,将逐一处理。但是,据我所知,一个代币不会在同一范围内扩展两次。因为它是"涂成蓝色"的。展开FUNCTION_TABLE_2时,宏FUNCTION_TABLE_1已经绘制完毕。为什么还在扩容?
类似函数的宏替换是一个递归过程:
- 宏首先以非递归方式扩展,除了
#
和##
- 然后,递归地展开任何不是
#
或##
操作数的令牌 #
和##
(如果有)应用于生成的操作数- 转到 1,直到步骤 1-3 不会导致任何更改。
(这比实现要复杂一些!因此,对于您的代码:
FUNCTION_TABLE((x) (y) (z) (e))
扩展到CAT(FUNCTION_TABLE_1 (x) (y) (z) (e), _END)
CAT(X, _END)
扩展到PRIMITIVE_CAT(expand(X), _END)
。现在expand(X)
锻炼:FUNCTION_TABLE_1 (x) (y) (z) (e)
扩展到FUNCTION(x) FUNCTION_TABLE_2 (y) (z) (e)
:FUNCTION(x)
扩展到void x();
FUNCTION_TABLE_2 (y) (z) (e)
扩展到FUNCTION(y) FUNCTION_TABLE_1 (z) (e)
FUNCTION(y)
扩展到void y();
FUNCTION_TABLE_1 (z) (e)
扩展到FUNCTION(z) FUNCTION_TABLE_2(e)
FUNCTION(z)
扩展到void z();
FUNCTION_TABLE_2(e)
扩展到FUNCTION(e) FUNCTION_TABLE_1
FUNCTION(e)
扩展到void e();
- 结果:
void e(); FUNCTION_TABLE_1
- 结果:
void z(); void e(); FUNCTION_TABLE_1
- 结果:
void y(); void z(); void e(); FUNCTION_TABLE_1
- 结果:
void x(); void y(); void z(); void e(); FUNCTION_TABLE_1
- 因此,完全扩展
X
,让我们回顾一下我们所处的位置:PRIMITIVE_CAT(void x(); void y(); void z(); void e(); FUNCTION_TABLE_1, _END)
- 这扩展到
void x(); void y(); void z(); void e(); FUNCTION_TABLE_1_END
- 重新扫描后,这会产生
void x(); void y(); void z(); void e();
这个想法是,在宏扩展中,所有参数的扩展都将以相同的 BLUE-SET 开始。
在FUNCTION_TABLE(seq)
内部FUNCTION_TABLE_1 seq
内所有参数的扩展将始终以 BLUE-SET={seq} 开始。因此,进入FUNCTION_TABLE_1后,BLUE-SET 将添加x
,但是当此操作完成后,它又回到了FUNCTION_TABLE
的范围,其中扩展再次从BLUE-SET={seq}
开始。
因此,第一次FUNCTION_TABLE_1(x)
扩展时,在此扩展中BLUE-SET={seq,x}
但是当FUNCTION_TABLE_1
的扩展结束时,它会返回到FUNCTION_TABLE
,并且接下来将从此范围扩展FUNCTION_TABLE_2(y)
和内部FUNCTION_TABLE_2
BLUE-SET={seq, x} 再次,依此类推。
相关文章:
- 钳制迭代器是否有效
- 在unordered_multimap中精确迭代一次每个键的有效方法
- 为什么以这种方式使用迭代器有效?
- 如何将迭代器(包括结束和开始之前的迭代器)测试到列表或forward_list保持有效
- 为什么序列迭代在 C 宏中有效?
- 索引与迭代器 - 哪个更有效?
- 在字符串中迭代单词的最有效方法
- 有效的迭代器范围从堆栈上的char
- 如何在迭代unordered_set时有效地替换元素
- 通过列表和转发列表进行迭代的最有效方法
- 如何普遍有效地填充缓冲液?(传递插入迭代器?器皿?等)
- 字符串::替换在有效的迭代器上抛出 std::out_of_range
- 迭代 Java 集合和对元素进行一些转换的有效方法
- 如何检查迭代器指定的范围是否有效
- 有效或无效的迭代程序和迭代程序位置
- 检查迭代器是否对QT容器有效
- 有效地使用python对象来迭代调用python函数的大型数据集
- 无法使用迭代器遍历字符串:但是我的带有索引的版本确实有效
- 根据内核/掩码在相关的相邻像素之间有效地迭代
- std::map::erase(it++)是否维护一个指向映射中下一个元素的有效迭代器