新版MSVC出现C++模板解析错误,GCC/LLVM及旧版MSVC正常,求答疑
问题:新版MSVC编译C++模板特化代码报错,是编译器bug还是代码无效?
近期将Microsoft Visual Studio升级至17.5.4(MSVC 19.35.32217)后,编译一段依赖模板特化的C++代码时出现编译错误,该代码可在最新版GCC、LLVM正常编译,也能在MSVC 19.34.31944版本下通过编译,且改编自一个多年跨平台运行的大型项目。
编译错误信息
bugtemplate.cpp(8,43): Error C2672: 'Test': no matching overloaded function found Bugtemplate.cpp(6,12): message : could be 'INT Test(size_t)' bugtemplate.cpp(9,1): message : 'INT Test(size_t)': could not deduce template argument for '__formal' bugtemplate.cpp(8,43): message : 'Test': function declaration must be available as none of the arguments depend on a template parameter
源码示例
#include <iostream> #include <cstdint> // General template template<typename INT, typename std::enable_if<std::is_integral<INT>::value>::type* = nullptr> inline INT Test(size_t x) { return static_cast<INT>(Test<uint64_t>(x)); } // Template specialization. template<> uint64_t Test<uint64_t>(size_t x) { return 0; } int main() { std::cout << Test<int>(0) << std::endl; }
结论:新版MSVC存在编译器bug,代码本身符合C++标准
这段代码是合法有效的C++代码,MSVC 19.35的报错属于编译器实现问题,原因如下:
- 通用模板中调用
Test<uint64_t>(x)是显式指定模板参数的调用,不属于依赖模板参数的推导场景,编译器应当允许在同一翻译单元后续位置查找该特化的定义。 - 根据C++标准,模板函数的显式特化只要在翻译单元内存在(无论定义在调用点之前还是之后,只要实例化时可见),就可以被合法调用。
- 旧版MSVC及其他主流编译器(GCC、LLVM)都能正确处理该代码,进一步说明这是新版MSVC的回归性bug。
临时解决方案
可以通过提前声明特化版本来规避该bug,修改后的代码如下:
#include <iostream> #include <cstdint> // 前置声明主模板 template<typename INT, typename std::enable_if<std::is_integral<INT>::value>::type* = nullptr> inline INT Test(size_t x); // 前置声明特化版本 template<> uint64_t Test<uint64_t>(size_t x); // 定义主模板 template<typename INT, typename std::enable_if<std::is_integral<INT>::value>::type* = nullptr> inline INT Test(size_t x) { return static_cast<INT>(Test<uint64_t>(x)); } // 定义特化版本 template<> uint64_t Test<uint64_t>(size_t x) { return 0; } int main() { std::cout << Test<int>(0) << std::endl; }
内容的提问来源于stack exchange,提问作者Thierry Lelegard
相关产品推荐
相关产品推荐

