为何返回可变参数模板类型的成员函数类外定义仅MSVC编译失败
编译差异原因分析
这个现象是MSVC编译器对嵌套于类模板的成员函数模板的类外定义的依赖类型匹配存在实现缺陷导致的,你的代码完全符合C++标准,GCC、Clang的编译行为是正确的。
具体原因拆解如下:
- 首先你写的类外定义语法完全合规:
typename DummyKO<T>::template AThing<U, Args...>是标准要求的写法,typename用于告诉编译器DummyKO<T>::AThing是一个类型名,template用于告诉编译器AThing是一个模板,这两个关键字在依赖外层模板参数T的场景下是必须的。 - MSVC的缺陷出在两层模板嵌套场景下的签名匹配逻辑:外层是类模板
DummyKO<T>,内层是成员函数模板GetAThing,返回值是类内嵌套的模板类AThing。MSVC的内部签名校验逻辑无法正确识别带template限定的依赖返回类型,哪怕错误日志里打印的定义和声明签名完全一致,也会错误判定匹配失败。 - 类内定义的
AnOtherGetAThing可以正常编译的原因:类内定义不需要写外层类限定前缀DummyKO<T>::,返回值AThing<U, Args...>直接在类模板作用域内查找,不需要处理依赖名称的前缀限定,所以避开了MSVC的逻辑缺陷。
MSVC下的兼容解决方案
你可以改用后置返回类型的写法绕开这个bug,不需要修改类内声明,仅修改类外定义即可:
template <typename T> template <typename U, typename... Args> auto DummyKO<T>::GetAThing() -> AThing<U, Args...> { return AThing<U, Args...>{}; }
后置返回类型会在类作用域下直接解析,不需要加typename和template前缀,可以规避MSVC的签名匹配问题。
内容的提问来源于stack exchange,提问作者Etienne M
相关产品推荐
相关产品推荐

