How to check whether a type is directly derived from another type?

Viewed 106

I know about std::is_base_of, but I want to allow just 1 level of inheritance.

class A
{
};

class B : public A
{
};

class C : public B
{
};

Is1LevelSubClass<A, C> -> false <- I want this!!!

Is1LevelSubClass<B, C> -> true

std::is_base_of<A, C> -> true

std::is_base_of<B, C> -> true

I'm working on MSVC, C++17

2 Answers

Putting aside how misguided this may be, the question as asked can still be answered.

It cannot be done out of the box. If you absolutely need this, you can get there by respecifying the immediate parent as a type member.

class A
{
public:
   using derived_from = void;
};

class B : public A
{
public:
   using derived_from = A;
};

class C : public B
{
public:
   using derived_from = B;
};

With that, Is1LevelSubClass<> is easy to implement:

template< class Base, class Derived >
struct Is1LevelSubClass : std::is_same<Base, typename Derived::derived_from> {};

template< class Base, class Derived >
constexpr bool Is1LevelSubClass_v = Is1LevelSubClass::value;

Demo: https://gcc.godbolt.org/z/zWjzb345c

Unfortunately, this requires language support for reflection, so it is currently not possible to do this in the standard.

However, you may be able to implement Is1LevelSubClass using tr2::direct_bases (originally from N2965) implemented by gcc.

#include <tr2/type_traits>

template<typename T>
struct direct_base { };
template<typename Base>
struct direct_base<std::tr2::__reflection_typelist<Base>> {
  using type = Base;
};
template<class B, class D>
constexpr inline bool Is1LevelSubClass = std::is_same_v<B, 
  typename direct_base<typename std::tr2::direct_bases<D>::type>::type>;

Demo.

Related