Home > Enterprise >  How to define a template function that only accepts a base class with parameter T of type its subcla
How to define a template function that only accepts a base class with parameter T of type its subcla

Time:02-20

It is not specific to casting. My scenario is how to define a template function that only accepts a base class for parameter T of type subclass.

template<typename T> // T must be a subclass
T* DoSomething(<I don't know> parent) // parent must be a base class
{
    // here the specified subclass of type T is produced.
    // return object of type T which is a subclass.
}

A contrived usage:

Parent* p = new Child();
Child* c = DoSomething<Child>(p);
delete p;

CodePudding user response:

One way could be by using std::is_base_of or std::is_base_of_v in combination with a static_assert:

template<typename Derived, typename Base>
Derived* CastChecked(Base* parent)
{
    static_assert(std::is_base_of_v<Base,Derived>);

    return dynamic_cast<Derived*>(parent);
}

CodePudding user response:

As you are not specifying a language version, I want to add the C 20 and beyond way is to use concepts. Your case is actually shown as an example on cpp reference.

For your case

#include <type_traits>

// concept
template <class D, class B>
concept Derived = std::is_base_of_v<B, D>;

template <typename D, typename B>
    requires Derived<D, B>
D* CastChecked(B* parent) {
    return dynamic_cast<D*>(parent);
}

struct Foo {};
struct Bar : Foo {};
struct Baz {};

int main() {
    auto foo{Foo{}};
    auto bar{&foo};

    auto const r{CastChecked<Foo>(bar)};

    auto baz{Baz{}};
    // auto const r{CastChecked<Foo>(baz)}; fails
}

However, you don't have to roll your own concept, as there's already a concept in the standard library: std::derived_from. So you can just write:

#include <concepts>

template <typename D, typename B>
    requires std::derived_from<D, B>
D* CastChecked(B* parent) {
    return dynamic_cast<D*>(parent);
}
  •  Tags:  
  • c
  • Related