可变参数宏在Clang运行正常但MSVC编译出错,求跨平台解决方案
差异原因
MSVC默认使用传统预处理器,其可变参数宏展开逻辑和Clang、GCC遵循的标准规则存在核心差异:传统MSVC预处理器会将__VA_ARGS__整体作为单个参数传递给下层宏,不会自动拆分为多个独立的参数项。
对应你的场景中,VA_NARGS_IMPL实际收到的首个参数是完整的T, 1串,而非拆分后的T、1两个参数,最终参数计数错误匹配到BENCHMARK1,把整个T,1作为结构体名传入后续宏,才会出现struct T, 1 : public Test的错误展开结果。
直接调用BENCHMARK2符合预期是因为没有经过__VA_ARGS__的间接传递,参数拆分逻辑不受预处理器差异影响。
跨平台兼容方案
方案1:开启MSVC标准预处理器(优先推荐)
VS 2019 16.5及以上版本(对应你使用的14.28编译器完全支持)可以在编译选项中添加/Zc:preprocessor,启用符合C++标准的预处理器,直接对齐Clang、GCC的宏展开行为,无需修改现有宏代码即可正常运行。
方案2:兼容传统MSVC预处理器的宏改写
如果不能修改编译选项,需要兼容旧版本MSVC,只需要给宏增加一层强制展开的间接层,强制__VA_ARGS__拆分参数即可。增加间接层后会强制MSVC预处理器在调用下层宏之前先展开__VA_ARGS__为独立参数,对齐标准预处理器的行为,修改后的完整宏代码如下:
// 新增强制展开辅助宏 #define EXPAND_MACRO(x) x #define VA_NARGS_IMPL(_1, _2, _3, _4, N, ...) BENCHMARK##N // 新增一层间接调用触发参数拆分 #define VA_NARGS(...) EXPAND_MACRO(VA_NARGS_IMPL(__VA_ARGS__, 4, 3, 2, 1)) #define BENCHMARK(...) EXPAND_MACRO(VA_NARGS(__VA_ARGS__)(__VA_ARGS__))
修改后无论使用标准预处理器还是传统MSVC预处理器,都可以正确展开得到预期结果。
内容的提问来源于stack exchange,提问作者Tyler Weiss
相关产品推荐
相关产品推荐

