Is there a way to identify whether or not a base class is a virtual base class?
std::is_base_of will identify a base class, but I'm looking for something like std::is_virtual_base_of to identify a virtual base class.
This is for SFINAE purposes where I want to use dynamic_cast (less performant) when std::is_virtual_base_of is true, and static_cast (more performant) when it is false.
namespace details {
template<template<class...>class, class, class...>
struct can_apply:std::false_type {};
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class... Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type {};
}
template<template<class...>class Z, class... Ts>
using can_apply = details::can_apply<Z, void, Ts...>;
this lets us do modular SFINAE on a template application easily.
template<class Dest, class Src>
using static_cast_r = decltype(static_cast<Dest>( std::declval<Src>() ));
template<class Dest, class Src>
using can_static_cast = can_apply< static_cast_r, Dest, Src >;
now we can determine if we can static cast.
Now we implement it:
namespace details {
template<class Dest, class Src>
Dest derived_cast_impl( std::true_type /* can static cast */ , Src&& src )
{
return static_cast<Dest>(std::forward<Src>(src));
}
template<class Dest, class Src>
Dest derived_cast_impl( std::false_type /* can static cast */ , Src&& src )
{
return dynamic_cast<Dest>(std::forward<Src>(src));
}
}
template<class Dest, class Src>
Dest derived_cast( Src&& src ) {
return details::derived_cast_impl<Dest>( can_static_cast<Dest, Src&&>{}, std::forward<Src>(src) );
}
Test code:
struct Base { virtual ~Base() {} };
struct A : virtual Base {};
struct B : Base {};
struct Base2 {};
struct B2 : Base2 {};
int main() {
auto* pa = derived_cast<A*>( (Base*)0 ); // static cast won't work
(void)pa;
auto* pb = derived_cast<B*>( (Base*)0 ); // either would work
(void)pb;
auto* pb2 = derived_cast<B2*>( (Base2*)0 ); // dynamic cast won't work
(void)pb2;
}