我有一个管理对象创建的类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*/}
答案 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"
}
}
虽然这可能不是最佳解决方案,因为它具有(微小的)运行时开销。一个非常聪明的编译器可能会通过静态分析消除这种开销,但我怀疑编译器会选择它。