Home > other >  How can I determine, if a templated class is a sublass of another templated class, as the templates
How can I determine, if a templated class is a sublass of another templated class, as the templates

Time:10-31

Consider the following class structure:

template <typename TType>
struct Base {public: virtual ~Base() {} };

template <typename TType>
struct Child : Base<TType> {};

template <template<typename> class Node, typename TType>
bool type(Node <TType>* node){
   return dynamic_cast<Base<TType>*>(node) == nullptr;
}

int main(){
   Child<int> child;
   type(&child);
}

This code works fine, as long as the child has the same template type before and after casting. If this is not the case, it will of course fail. If they have different types and I provide the specific type of the inherited template, it will work, but I have a very big number of possible templates. My first instinct was to add another template:

template <template<typename TType> class Node, typename TType, typename TType2>
bool type(Node <TType>* node){
   return dynamic_cast<Base<TType2>*>(node) == nullptr;
}

This will give an error "couldn't deduce template parameter", because the compiler does not know which type it is, as no corresponding parameter is passed (but I am not able to provide this in beforehand).

Is there any solution to this? I am also open to other possibilites than dynamic_cast, as my actual goal is, if the templated node is a subclass of the also templated baseclass.

I tried e.g. is_base_of without success. Something around the lines of is_base_of<Base, typeid(child)>::value did not work because of a type msimatch in the arguments.

CodePudding user response:

You might use overload:

template <typename T>
constexpr std::true_type IsBaseT(const Base<T>*) { return {}; }

constexpr std::false_type IsBaseT(const void*) { return {}; }

Demo

That assumes accessible, non ambiguous base. And result is based on static type.

So you can turn that into a traits:

template <typename T>
std::true_type IsBaseTImpl(const Base<T>*); // No impl
std::false_type IsBaseTImpl(const void*); // No impl

template <typename T>
using IsBaseT = decltype(IsBaseTImpl(std::declval<T*>()));

And a more generic form:

template <template <typname> C, typename T>
std::true_type IsCTImpl(const C<T>*); // No impl
template <template <typname> C>
std::false_type IsCTImpl(const void*); // No impl

template <template <typname> C, typename T>
using IsCT = decltype(IsCTImpl<C>(std::declval<T*>()));

template <typename T>
using IsBaseT = IsCT<Base, T>;
  • Related