如何用C预处理器生成X宏列表自笛卡尔积且无需重复定义列表?
问题:利用C预处理器生成X宏列表的自笛卡尔积代码
假设我们用X宏定义了如下类型列表:
#define TYPES(X, ...) \ X(__VA_ARGS__, i, int) \ X(__VA_ARGS__, j, unsigned int) \ X(__VA_ARGS__, l, long) \ X(__VA_ARGS__, m, unsigned long)
当前的做法是复制一份列表宏命名为TYPES_,再通过TYPES_(TYPES, CAST)生成所有类型对的转换函数:
#define TYPES_(X, ...) \ X(__VA_ARGS__, i, int) \ X(__VA_ARGS__, j, unsigned int) \ X(__VA_ARGS__, l, long) \ X(__VA_ARGS__, m, unsigned long) #define CAST(FROMCH, FROMTY, TOCH, TOTY) \ TOTY FROMCH ## to ## TOCH (FROMTY x) { return (TOTY)x; } TYPES_(TYPES, CAST)
但直接使用TYPES会触发预处理器递归展开的限制,无法运行。我们需要一种无需重复定义列表、也不依赖特殊预处理器扩展的方法,生成列表的自笛卡尔积代码。
解决方案:拆分列表定义与调用逻辑
核心思路是把纯列表内容和X宏调用逻辑拆分开,避免递归展开的问题:
- 首先定义仅包含列表项的宏
TYPES_LIST,这是唯一需要维护的数据源:
#define TYPES_LIST(X, ...) \ X(__VA_ARGS__, i, int) \ X(__VA_ARGS__, j, unsigned int) \ X(__VA_ARGS__, l, long) \ X(__VA_ARGS__, m, unsigned long)
- 原有的
TYPES宏改为对TYPES_LIST的简单包装,保持原有用法兼容:
#define TYPES(X, ...) TYPES_LIST(X, __VA_ARGS__)
- 定义中间宏实现双层遍历:外层遍历每个源类型,内层遍历每个目标类型,生成转换函数:
// 外层遍历源类型时,调用此宏触发内层的目标类型遍历 #define GEN_CAST_FROM(FROMCH, FROMTY) TYPES_LIST(CAST, FROMCH, FROMTY) // 单个转换函数的生成宏 #define CAST(FROMCH, FROMTY, TOCH, TOTY) \ TOTY FROMCH ## to ## TOCH (FROMTY x) { return (TOTY)x; } // 生成所有类型对的转换函数 TYPES(GEN_CAST_FROM)
原理说明
TYPES(GEN_CAST_FROM)会展开为对每个源类型(i/j/l/m)调用GEN_CAST_FROM;- 每个
GEN_CAST_FROM(FROMCH, FROMTY)又会调用TYPES_LIST(CAST, FROMCH, FROMTY),即对每个目标类型(i/j/l/m)调用CAST宏; - 最终生成4×4=16个类型转换函数,完全覆盖自笛卡尔积,且全程没有递归展开问题——因为
TYPES和TYPES_LIST是分离的,不会出现宏自身调用自身的情况。
这种方法仅使用标准C预处理器特性,不需要重复维护列表,后续修改类型仅需更新TYPES_LIST即可。
内容的提问来源于stack exchange,提问作者Alex Shpilkin
相关产品推荐
相关产品推荐

