带decltype参数的函数显式实例化在GCC/Clang正常但MSVC报错
C++20 带auto参数的成员函数模板显式实例化在MSVC中的编译问题
问题概述
你编写的这段C++20代码,使用带concept约束的auto参数定义成员函数模板并尝试显式实例化,在GCC、Clang(x86-64 trunk,-std=c++20)中可正常编译,但在MSVC(x64 v19.latest /std:c++20)中触发C3190和C2945错误。
代码示例
#include <cstdint> #include <concepts> template <typename T> concept MyType = std::same_as<T,uint16_t> || std::same_as<T,uint32_t>; class A { public: void Foo(uint32_t arg1, MyType auto arg2); void Bar(uint32_t agr1, MyType auto arg2, decltype(arg2) arg3); }; void A::Foo(uint32_t arg1, MyType auto arg2) {} // 定义 template void A::Foo(uint32_t, uint16_t); // 显式实例化uint16_t版本 template void A::Foo(uint32_t, uint32_t); // 显式实例化uint32_t版本 void A::Bar(uint32_t arg1, MyType auto arg2, decltype(arg2) arg3) {} // 定义 template void A::Bar(uint32_t, uint16_t, uint16_t); // 显式实例化uint16_t版本 template void A::Bar(uint32_t, uint32_t, uint32_t); // 显式实例化uint32_t版本 int main() {}
MSVC错误信息
(26): error C3190: 'void A::Bar(uint32_t,uint16_t,uint16_t)' with the provided template arguments is not the explicit instantiation of any member function of 'A' (26): error C2945: explicit instantiation does not refer to a template-class specialization (27): error C3190: 'void A::Bar(uint32_t,uint32_t,uint32_t)' with the provided template arguments is not the explicit instantiation of any member function of 'A' (27): error C2945: explicit instantiation does not refer to a template-class specialization.
原因分析
你的写法完全符合C++20标准,这是MSVC的编译器bug。
C++20允许用auto参数定义函数模板,且decltype(arg2)这种依赖于前面auto参数的类型,应当被推导为与arg2关联的同一模板参数。GCC和Clang都正确实现了这一规则,但MSVC在解析Bar的模板签名时,未能识别decltype(arg2)与arg2属于同一模板参数,导致显式实例化时无法匹配对应的模板函数。
解决办法
最可靠的解决方式是显式写出模板参数列表,替代auto参数的写法,让MSVC能清晰识别模板参数:
修改后的代码如下:
#include <cstdint> #include <concepts> template <typename T> concept MyType = std::same_as<T,uint16_t> || std::same_as<T,uint32_t>; class A { public: void Foo(uint32_t arg1, MyType auto arg2); // 显式声明模板参数T,替代auto参数写法 template <MyType T> void Bar(uint32_t arg1, T arg2, T arg3); }; void A::Foo(uint32_t arg1, MyType auto arg2) {} template void A::Foo(uint32_t, uint16_t); template void A::Foo(uint32_t, uint32_t); // 显式定义模板函数 template <MyType T> void A::Bar(uint32_t arg1, T arg2, T arg3) {} // 显式指定模板参数进行实例化 template void A::Bar<uint16_t>(uint32_t, uint16_t, uint16_t); template void A::Bar<uint32_t>(uint32_t, uint32_t, uint32_t); int main() {}
这种写法完全符合标准,所有主流编译器都能正确处理。
内容的提问来源于stack exchange,提问作者NKatUT
相关产品推荐
相关产品推荐

