2013-10-28 160 views
0

有没有办法定义一个模板类,只能用于特定类层次结构的派生类?类层次结构的模板类?

说我有动物基类

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

和狗,猫,虎都派生类

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

我需要定义一个模板类说,只能使用“AnimalTemplate”派生类动物,所以如果我尝试做'动物模板<鸭'>,我应该得到编译错误(或一些错误),即使鸭有一个方法shout()定义在它。 (这个问题主要是为了解我们是否可以将OO范式与Generic编程混合)

+3

等等,是不是也是鸭子的动物呢? – DanielKO

+0

对于这个讨论可以说,鸭子不是动物,他们从不同的基类叫()鸟叫。 :) – Coder777

+1

你使用的是C++ 11吗?如果是这样,你可以使用[std :: is_base_of](http://en.cppreference.com/w/cpp/types/is_base_of)和[static_assert](http://en.cppreference.com/w/cpp/ language/static_assert) –

回答

2

您可以简单地定义模板,使其使用模板参数作为Animal。例如:

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

在模板参数不匹配的情况下生成错误通常相当平凡。如果有任何总是实例化的方法,例如析构函数,那也可能是支票可能出现的地方。

+0

对不起,我不理解后面的代码和解释。你能再解释一下吗? (道歉,如果这在泛型编程世界中非常普遍) – Coder777

+0

好的,这个想法是使用从T *到'Animal *'的隐式转换,只有当'T'从'Animal'公开派生时才存在(使用'static_casts()'我最初实际上也是从base或'void *'转换为派生的)。上面的隐式转换放在一个'sizeof()'表达式中,以确保它不被评估。 –

+0

实际上并没有使用'bool'参数:当'T'参数不适用时,代码就会失败。 –

4

两种形式的这立刻浮现在脑海:

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

后者是在告诉你为什么会失败,显然是友好的。

+0

为了完整,标签调度的专业? – Yakk

+0

@Yakk是的,我应该补充一下,只是想到一些有创意的名字(因为某些原因,Looney Toonz的人物正在思考)。 – WhozCraig

0

如果animalTemplate功能模板,你可以只是做:

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

最常模板放心使用正确的用户输入。这被称为鸭子打字。 (适合您的情况!)有关未来C++的定义概念的工作,可用于指定模板可以采用何种输入。