Reputation: 1035
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
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
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
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