解析cppreference中std::is_base_of实现:私有继承下为何需声明3?
std::is_base_of实现中声明3的必要性解析
参考实现代码
取自cppreference.com的std::is_base_of模板实现:
namespace details { template <typename B> std::true_type test_pre_ptr_convertible(const B*); //1 template <typename> std::false_type test_pre_ptr_convertible(const void*); //2 template <typename, typename> auto test_pre_is_base_of(...)->std::true_type; //3 template <typename B, typename D> auto test_pre_is_base_of(int) -> decltype(test_pre_ptr_convertible<B>(static_cast<D*>(nullptr))); } template <typename Base, typename Derived> struct is_base_of : std::integral_constant< bool, std::is_class<Base>::value&& std::is_class<Derived>::value&& decltype(details::test_pre_is_base_of<Base, Derived>(0))::value > { };
私有继承测试场景
class A {}; class B : A {};
此时is_base_of<A,B>::value返回true,且匹配的是声明3。以下是核心问题的解析:
为什么必须保留声明3?
在私有继承场景下,static_cast<B*>(nullptr)转换为const A*(声明1的参数类型)是访问权限不允许的——私有继承的基类指针转换只能在子类内部执行,外部代码(包括这个模板实现)没有权限完成该转换。
此时带int参数的test_pre_is_base_of重载,其返回类型依赖test_pre_ptr_convertible<B>(static_cast<D*>(nullptr))的推导,但这个表达式因权限问题直接非法,编译器会彻底排除该重载。
如果没有声明3,details::test_pre_is_base_of<Base, Derived>(0)就找不到任何合法重载,直接触发编译错误。而声明3是优先级最低的万能重载(使用...参数包),只要其他重载不可用,编译器就会匹配它,既保证代码能正常编译,又返回std::true_type——这也符合语义:A确实是B的基类,只是继承权限为私有。
为什么声明1和2不足以满足需求?
- 声明1要求能将
D*转换为const B*,但私有继承下该转换在外部非法,导致此重载的推导失败; - 声明2的参数是
const void*,但test_pre_ptr_convertible<B>是针对B实例化的模板,它的参数类型是const B*而非const void*——既然连D*转const B*都做不到,自然也无法匹配到声明2。
简言之,私有继承场景下,带int参数的重载完全不可用,必须靠声明3这个兜底重载维持编译合法性,并输出正确的语义结果。
内容的提问来源于stack exchange,提问作者mcz
相关产品推荐
相关产品推荐

