C++延迟展开宏层级理解验证及细节疑问咨询
C++宏延迟展开的理解验证与细节补充
你的理解逻辑合理性分析
你的核心思路是通过EMPTY()宏触发额外展开阶段,配合EVAL_N系列宏控制展开层级,用DEFER_N系列宏实现宏调用的延迟拼接,这个方向是对的,大部分代码注释的逻辑也符合预处理器展开规则,但存在几处细节误解:
Line 2的错误判断偏差
你认为EVAL_1(DEFER2(A)(5))会展开为A(5)并报错,但实际预处理器会完成完整展开:DEFER2(A)(5)的展开流程:DEFER2(A)→A DEFER(EMPTY) ()→A EMPTY EMPTY() (),拼接(5)后得到A EMPTY EMPTY() () (5);- 经过
EVAL_1展开时,预处理器会递归展开所有EMPTY():先展开最内层EMPTY()为空 →A EMPTY () (5),再展开EMPTY()为空 →A (5),最终A(5)展开为5,不会报错。
Line 3/4的展开结果误解
以DEFER3(A)(5)为例,展开后会经过多层EMPTY()的逐步剥离,最终在EVAL_1中会完全展开为A(5)并得到5,而非你注释中的A EMPTY() (5)。
遗漏的预处理器展开细节
宏展开的递归终止规则
预处理器对宏的展开是深度优先的递归扫描,除非遇到#/##操作符,或者宏是自引用的(如#define FOO FOO),否则会持续展开直到没有可展开的宏为止。你的EMPTY()是非自引用的空宏,每次遇到都会被完全展开为空,不会残留。延迟展开的核心本质
你实现的DEFER系列宏的延迟效果,本质是通过插入EMPTY()打断当前展开阶段的宏拼接,让原本会直接拼接成A(5)的代码变成A EMPTY()(5),迫使预处理器需要多一次扫描才能完成A(5)的拼接:DEFER(A)(5)→A EMPTY()(5),一次扫描展开EMPTY()就能得到A(5),完成一次延迟;DEFER2(A)(5)→A EMPTY EMPTY() () (5),需要两次扫描才能逐步剥离EMPTY(),完成两次延迟。
EVAL_N与DEFER_N的层级匹配
EVAL_N的展开层级需要和DEFER_N的延迟层级对应:DEFER需要1层EVAL即可完全展开;DEFER2需要2层EVAL才能确保所有EMPTY()被展开并完成宏拼接;
你代码中Line 6的EVAL_2(DEFER2(A)(5))能正确得到5,就是因为两层展开刚好匹配两次延迟。
修正后的验证代码
以下是修正注释后的代码,实际运行可验证展开逻辑:
// Online C++ compiler to run C++ program online #include <iostream> #define EMPTY() #define EVAL_1(...) __VA_ARGS__ #define EVAL_2(...) EVAL_1(EVAL_1(__VA_ARGS__)) #define EVAL_3(...) EVAL_1(EVAL_2(__VA_ARGS__)) #define EVAL_4(...) EVAL_1(EVAL_3(__VA_ARGS__)) #define DEFER(...) __VA_ARGS__ EMPTY() #define DEFER2(...) __VA_ARGS__ DEFER(EMPTY) () #define DEFER3(...) __VA_ARGS__ DEFER2(EMPTY) () #define DEFER4(...) __VA_ARGS__ DEFER3(EMPTY) () #define A(x) x int main() { // 1层展开:直接完成DEFER的延迟展开 std::cout << (EVAL_1(DEFER(A)(5))) << std::endl; // 输出5 // 1层展开:完成DEFER2的所有EMPTY()展开,最终得到A(5)→5 std::cout << (EVAL_1(DEFER2(A)(5))) << std::endl; // 输出5 // 1层展开:完成DEFER3的所有EMPTY()展开,最终得到A(5)→5 std::cout << (EVAL_1(DEFER3(A)(5))) << std::endl; // 输出5 // 1层展开:完成DEFER4的所有EMPTY()展开,最终得到A(5)→5 std::cout << (EVAL_1(DEFER4(A)(5))) << std::endl; // 输出5 // 2层展开:重复展开,结果不变 std::cout << (EVAL_2(DEFER(A)(5))) << std::endl; // 输出5 std::cout << (EVAL_2(DEFER2(A)(5))) << std::endl; // 输出5 std::cout << (EVAL_2(DEFER3(A)(5))) << std::endl; // 输出5 std::cout << (EVAL_2(DEFER4(A)(5))) << std::endl; // 输出5 return 0; }
内容的提问来源于stack exchange,提问作者rishabh thakkar
相关产品推荐
相关产品推荐

