MSVC模板基类typedef与模板参数命名冲突及非重命名解决方案问询
MSVC模板参数与基类成员名冲突的兼容解决方案
以下代码在GCC、Clang等主流编译器中可正常编译,但使用MSVC v19版本、以/std:c++17选项编译时会触发访问权限错误:
template<typename T> class base { private: using foo = T; }; template<typename foo> class A : public base<foo> { public: using bar = foo; }; int main() { A<int> a; }
MSVC编译错误信息:
example.cpp <source>(12): error C2248: 'base<foo>::foo': cannot access private typedef declared in class 'base<foo>' with [ foo=int ] <source>(5): note: see declaration of 'base<foo>::foo' with [ foo=int ] <source>(9): note: see declaration of 'base<foo>' with [ foo=int ] <source>(17): note: see reference to class template instantiation 'A<int>' being compiled Compiler returned: 2
问题根源是MSVC在解析派生类A中的foo时,错误地将其绑定到基类base<foo>的私有typedef成员,而非A的模板参数。以下是无需重命名模板参数的兼容方案:
解决方案:使用类型标识模板(Type Identity)
通过引入一个简单的类型标识模板,明确告诉编译器我们引用的是模板参数而非基类成员:
// C++17及更早版本需自行实现类型标识模板(C++20可直接用std::type_identity_t) template<typename T> struct type_identity { using type = T; }; template<typename T> using type_identity_t = typename type_identity<T>::type; template<typename T> class base { private: using foo = T; }; template<typename foo> class A : public base<foo> { public: // 通过type_identity_t明确引用模板参数foo using bar = type_identity_t<foo>; }; int main() { A<int> a; }
方案原理:
类型标识模板type_identity的作用是将输入类型原样返回。由于模板参数foo作为实参传入type_identity时,编译器会优先解析为当前模板的参数,而非基类的成员,从而避开MSVC的解析错误。该方案完全符合C++标准,同时兼容所有主流编译器。
内容的提问来源于stack exchange,提问作者Jakub Klinkovský
相关产品推荐
相关产品推荐

