Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a templated method allowing only subclasses as parameter

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?

like image 529
Pierluigi Avatar asked Dec 24 '22 14:12

Pierluigi


1 Answers

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.

like image 62
TartanLlama Avatar answered Dec 31 '22 07:12

TartanLlama