Here we have is_base_of
template implementation taken from cppreference.com:
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
> { };
And some private inheritance:
class A {};
class B : A {};
is_base_of<A,B>::value
gives true and declaration no. 3 is the best match. Declaration no. 1 fails as a candidate(was passed a pointer to object of private subclass) and declaration no. 2 is ignored. But Why? Isn't void*
a good match for every pointer type? If declaration no. 3 was not provided the code wouldn't compile. My question is why declaration no. 3 needs to be provided for this code to compile successfully? Why declarations no. 1 and no. 2 aren't sufficient?