Coder777
Coder777

Reputation: 1035

Template class for class hierarchy?

Is there a way to define a template class that can be used only with derived classes from a particular class hierarchy?

Say I have Animal base class

class Animal{
    public:
        virtual ~Animal();
        virtual void shout() = 0;
    };

and Dog, Cat,Tiger are derived classes

class Dog : public Animal{
    public:
    virtual void shout(){
        cout<<"Bark";
    }
}
class Cat : public Animal{
    public:
    virtual void shout()
    {
        cout<<"Meow";
    }
}

I need to define a template class say 'AnimalTemplate' that can be used ONLY with the derived class of Animal, so if I try to do 'AnimalTemplate< Duck >', I should get compilation error( or some error ), even if Duck has a method shout() defined in it. (This question is mainly for me to understanding if we can mix OO paradigm with Generic programming)

Upvotes: 0

Views: 1019

Answers (3)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153810

You can simple define your template in such a way that it uses the template argument as an Animal. For example:

template <typename T,
          bool = sizeof(*static_cast<Animal**>(0) = static_cast<T*>(0))>
class AnimalTemplate
{
    // whatever
};

Producing an error in case a template argument doesn't match is generally fairly trivial. If there is any method which is always instantiated, e.g., the destructor, that could be a palce where the check could go, too.

Upvotes: 2

Johan Lundberg
Johan Lundberg

Reputation: 27038

If animalTemplate is a function template you could just do:

template<typename T> void animalTemplate(T animal_candidate){
   auto& animal= static_cast<Animal&>(animal_candidate);
   animal.shout();
}

Most often templates trust the user to use the correct input. This is known as duck typing. (suiting for your case!) There is work for future C++ on defining Concepts, which may be used to specify what kind of input a template can take.

Upvotes: 0

WhozCraig
WhozCraig

Reputation: 66194

Two forms of this immediately come to mind:

SFINAE

template<typename T, 
         typename = typename std::enable_if<std::is_base_of<Animal,T>::value>::type>
class AnimalTemplate
{
public:
    AnimalTemplate() {}
};

static_assert

template<typename T>
class AnimalTemplate
{
public:
    static_assert(std::is_base_of<Animal,T>::value, "T must be derived from Animal");
    AnimalTemplate() {}
};

The latter is friendlier in telling you why it failed, obviously.

Upvotes: 4

Related Questions