如何为从特定类型派生的类型专门化模板

时间:2012-03-30 11:27:13

标签: c++ templates

我有一个管理对象创建的类World ...创建后它调用afterCreation方法,我创建的对象是从实体派生的用户定义类型(例如MyEntity ),我想打电话给addEntity。我的对象是别的,我什么都不做。 必须使用适当的addEntity调用T,因为它会为每个派生类等生成唯一ID。

这是我的解决方案:

template <int v>
struct ToType
{
    enum { value = v };
};

template <typename T>
void World::afterCreation(T * t)
{
    afterCreation(t, ToType<std::is_base_of<Entity, T>::value>());
}

template <typename T>
void World::afterCreation(T * t, ToType<true>)
{
    addEntity(t); //here I cant pass Entity *, I need the real type, eg. MyEntity
}

template <typename T>
void World::afterCreation(T * t, ToType<false>)
{

}

我的问题是 - 可以做得更好吗?

如何在没有ToType或类似内容的情况下模拟以下代码?

template <typename T>
void afterCreation(){/*generic impl*/}

template <typename T where T is derived from Entity>
void afterCreation(){/*some specific stuff*/}
    标题中的
  • “specialize”只是为了描述我的意图,不需要用模板专业化解决问题

2 个答案:

答案 0 :(得分:3)

它不会更好,但你可以使用SFINAE删除一个间接级别:

template <typename T>
typename std::enable_if< std::is_base_of<Entity, T>::value >::type
 World::afterCreation(T * t)
{
   // Derived from Entity
}
template <typename T>
typename std::enable_if< !std::is_base_of<Entity, T>::value >::type
 World::afterCreation(T * t)
{
   // generic
}

这是如何工作的?当编译器找到对afterCreation的调用时,它会尝试确定哪个重载 best ,并且为了匹配类型并尝试执行替换。在这两种情况下,匹配类型(来自参数)并将替换应用于整个表达式。如果作为第一个参数传递的值为enable_if,则type模板包含内部类型true,否则它不包含此类型。在替换类型时,其中一个重载将产生一个无效的函数签名(条件为false的函数签名),并将从候选集中删除。

答案 1 :(得分:1)

您可以使用多态指针执行此操作:

template <typename T>
void afterCreation(T* x) {
    T* entity = dynamic_cast<Entity*> x;

    if (!entity) {
        // ... generic implementation
    } else {
        // ... entity implementation, use "entity"
    }
}

虽然这可能不是最佳解决方案,因为它具有(微小的)运行时开销。一个非常聪明的编译器可能会通过静态分析消除这种开销,但我怀疑编译器会选择它。