Suppose I have set of classes inheriting from a single superclass S:
class S{ ... };
class C1 : public S{ ... };
class C2 : public S{ ... };
Then suppose I have a templated method:
template<class T> void foo(T* instance);
I would like to statically check that foo is never called providing an instance of the superclass but only called providing one of the (concrete) subclasses (e.g. explicitly calling foo<C1>(x)
for instance)
Is this possible?
First we can write a trait to check if T
is derived from S
, but not S
:
template <class Base, class Derived>
using is_strict_base =
std::integral_constant<bool,
std::is_base_of<Base,Derived>::value &&
!std::is_same<Base,typename std::remove_cv<Derived>::type>::value>;
You can use std::enable_if
to use this trait:
template<class T>
typename std::enable_if<is_strict_base<S,T>::value>::type
foo(T* instance)
{}
With C++14 you can use std::enable_if_t
to make it a bit prettier:
template<class T>
std::enable_if_t<is_strict_base<S,T>::value>
foo(T* instance)
{}
Another option is to use static_assert
:
template<class T>
void foo(T* instance)
{
static_assert(is_strict_base<S,T>::value,
"T must be derived from S, but not S");
}
This gives you a nicer error, but I personally believe that type constraints for a function belong in the declaration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With