MSVC误判私有继承类重定义成员可访问性问题及兼容方案咨询
MSVC 私有继承场景下静态成员访问兼容方案
问题描述
以下代码在GCC、Clang等主流编译器中可正常编译,但使用MSVC v19开启/std:c++17 /permissive-选项编译时,会触发私有继承相关的访问权限错误:
#include <cstddef> template< std::size_t... sizes > class Impl { public: static constexpr std::size_t getDimension() { return sizeof...( sizes ); } }; template< std::size_t... sizes > class Wrapper : private Impl< sizes... > { using BaseType = Impl< sizes... >; public: static constexpr std::size_t getDimension() { return BaseType::getDimension(); } }; template< typename A, typename B > class Combine : public B { public: static_assert( A::getDimension() > 0 ); static_assert( B::getDimension() > 0 ); static_assert( A::getDimension() == B::getDimension(), "dimensions of A and b do not match" ); }; int main() { Combine< Impl< 0 >, Wrapper< 0 > > a; }
MSVC报错信息:
example.cpp <source>(32): error C2247: 'Impl<0>::getDimension' not accessible because 'Wrapper<0>' uses 'private' to inherit from 'Impl<0>' <source>(8): note: see declaration of 'Impl<0>::getDimension' <source>(40): note: see declaration of 'Wrapper<0>' <source>(40): note: see declaration of 'Impl<0>' <source>(32): error C2248: 'Impl<0>::getDimension': cannot access private member declared in class 'Wrapper<0>' <source>(8): note: see declaration of 'Impl<0>::getDimension' <source>(40): note: see declaration of 'Wrapper<0>' <source>(40): note: see reference to class template instantiation 'Combine<Impl<0>,Wrapper<0>>' being compiled <source>(34): error C2247: 'Impl<0>::getDimension' not accessible because 'Wrapper<0>' uses 'private' to inherit from 'Impl<0>' <source>(8): note: see declaration of 'Impl<0>::getDimension' <source>(40): note: see declaration of 'Wrapper<0>' <source>(40): note: see declaration of 'Impl<0>' <source>(34): error C2248: 'Impl<0>::getDimension': cannot access private member declared in class 'Wrapper<0>' <source>(8): note: see declaration of 'Impl<0>::getDimension' <source>(40): note: see declaration of 'Wrapper<0>' Compiler returned: 2
问题根源是MSVC在处理B::getDimension()时,错误地尝试通过Wrapper的私有基类Impl解析该成员,而非直接使用Wrapper自身公开的getDimension成员函数。
兼容方案
方案1:使用辅助模板封装维度获取逻辑
通过独立的辅助模板来获取类型维度,绕过MSVC的错误访问检查,且无需修改私有继承结构:
#include <cstddef> template< std::size_t... sizes > class Impl { public: static constexpr std::size_t getDimension() { return sizeof...( sizes ); } }; template< std::size_t... sizes > class Wrapper : private Impl< sizes... > { using BaseType = Impl< sizes... >; public: static constexpr std::size_t getDimension() { return BaseType::getDimension(); } }; // 新增辅助模板,封装维度获取逻辑 template<typename T> struct GetDimension { static constexpr std::size_t value = T::getDimension(); }; template< typename A, typename B > class Combine : public B { public: static_assert( GetDimension<A>::value > 0 ); static_assert( GetDimension<B>::value > 0 ); static_assert( GetDimension<A>::value == GetDimension<B>::value, "dimensions of A and b do not match" ); }; int main() { Combine< Impl< 0 >, Wrapper< 0 > > a; }
方案2:显式强化Wrapper的成员归属(可选增强)
在Wrapper中添加额外的公开标识,辅助MSVC正确识别成员归属,配合辅助模板使用效果更稳定:
template< std::size_t... sizes > class Wrapper : private Impl< sizes... > { using BaseType = Impl< sizes... >; public: static constexpr std::size_t getDimension() { return BaseType::getDimension(); } // 可选:添加公开类型别名,明确成员归属 using DimensionReturnType = std::size_t; };
内容的提问来源于stack exchange,提问作者Jakub Klinkovský
相关产品推荐
相关产品推荐

