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);
}