C++宏内拼接编译报错:未声明标识符APPLY_TO_VARIADIC_PAIRS_IMPL_VA_NARGS
C++宏拼接操作编译错误分析与解决
尝试在C++宏中实现参数对的拼接操作,编写了如下代码:
#include <cstdio> #include <iostream> #define BOILERPLATE(STAGE, REQ_COMP_FUNC) \ REQ_COMP_FUNC; \ STAGE; #define REGIS(...) \ void regi() \ { \ APPLY_TO_VARIADIC_PAIRS_IMPL(BOILERPLATE, VA_NARGS(__VA_ARGS__), __VA_ARGS__) \ } #define APPLY_TO_VARIADIC_PAIRS_IMPL(func, n, ...) \ static_assert(n==2); \ APPLY_TO_VARIADIC_PAIRS_IMPL_##n(func, __VA_ARGS__) #define APPLY_TO_VARIADIC_PAIRS_IMPL_2(func, x, y) \ func(x, y) #define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) REGIS(std::cout << "HEY", std::cout << "HEY"); int main() { }
编译时出现如下错误:
error: use of undeclared identifier 'APPLY_TO_VARIADIC_PAIRS_IMPL_VA_NARGS'
问题原因
错误根源在于宏的预处理顺序:C++预处理阶段中,宏字符串拼接操作(##)的优先级高于宏参数的替换。在APPLY_TO_VARIADIC_PAIRS_IMPL宏里,APPLY_TO_VARIADIC_PAIRS_IMPL_##n会直接把符号n与前缀拼接,而此时n对应的VA_NARGS(__VA_ARGS__)还未展开为具体数字2,最终生成了非法的APPLY_TO_VARIADIC_PAIRS_IMPL_VA_NARGS标识符。
需要注意的是,static_assert(n==2)是编译期检查,而宏展开是预处理阶段操作,因此static_assert无法影响预处理时的宏拼接逻辑。
解决方案
添加一层辅助宏,让VA_NARGS先完成展开,再执行拼接操作。修改后的代码如下:
#include <cstdio> #include <iostream> #define BOILERPLATE(STAGE, REQ_COMP_FUNC) \ REQ_COMP_FUNC; \ STAGE; #define REGIS(...) \ void regi() \ { \ APPLY_TO_VARIADIC_PAIRS_IMPL(BOILERPLATE, VA_NARGS(__VA_ARGS__), __VA_ARGS__) \ } // 新增辅助宏,触发参数展开后再拼接 #define APPLY_TO_VARIADIC_PAIRS_HELPER(func, n, ...) \ APPLY_TO_VARIADIC_PAIRS_IMPL_##n(func, __VA_ARGS__) #define APPLY_TO_VARIADIC_PAIRS_IMPL(func, n, ...) \ static_assert(n==2); \ APPLY_TO_VARIADIC_PAIRS_HELPER(func, n, __VA_ARGS__) #define APPLY_TO_VARIADIC_PAIRS_IMPL_2(func, x, y) \ func(x, y) #define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) REGIS(std::cout << "HEY", std::cout << "HEY"); int main() { }
改动说明
新增的APPLY_TO_VARIADIC_PAIRS_HELPER宏作为中间层:当APPLY_TO_VARIADIC_PAIRS_IMPL调用它时,参数n会先被展开为VA_NARGS的结果(即2),随后HELPER宏里的##操作才会把APPLY_TO_VARIADIC_PAIRS_IMPL_与2拼接成合法的APPLY_TO_VARIADIC_PAIRS_IMPL_2,最终正确调用目标宏。
内容的提问来源于stack exchange,提问作者ATK
相关产品推荐
相关产品推荐

