2012-03-30 10 views
5

Tengo la clase World que gestiona la creación del objeto ... Después de la creación, llama al método afterCreation y el objeto creado es de tipo definido por el usuario derivado de la entidad (por ejemplo MyEntity), Quiero llamar al addEntity. Yo el objeto era otra cosa, no quiero hacer nada. addEntity debe ser llamado con T adecuada, ya que genera identificadores únicos para cada clase derivada etc.Cómo especializar la plantilla para el tipo derivada del tipo particular

Aquí está mi solución:

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>) 
{ 

} 

Mi pregunta es - ¿Puede hacerse en forma mejor?

¿Cómo puedo simular el código siguiente sin ToType o similar?

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

template <typename T where T is derived from Entity> 
void afterCreation(){/*some specific stuff*/} 
  • "especializan" en el título es sólo para describir mi intención, no hay necesidad de resolver un problema en esta especialización de plantilla

Respuesta

3

no va a hacer que sea mucho mejor, pero se puede quitar un nivel de indirección utilizando 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 
} 

¿Cómo funciona esto? Cuando el compilador encuentra la llamada al afterCreation, intenta determinar cuál de las sobrecargas es mejor, y para eso coincide con los tipos e intenta realizar la sustitución. En ambos casos, el tipo coincidente (de los argumentos) y aplicar la sustitución a la expresión completa. La plantilla enable_if contiene un tipo interno type si el valor pasado como primer argumento es true o si no contiene dicho tipo. Durante la sustitución de los tipos, una de las sobrecargas producirá una firma de función no válida (aquella para la que la condición es falsa) y se eliminará del conjunto de candidatos.

1

Usted puede hacer esto con los punteros polimórficas:

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

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

Aunque esta podría no ser la mejor solución, ya que tiene una sobrecarga de tiempo de ejecución (pequeña). Un compilador muy inteligente podría eliminar esta sobrecarga a través del análisis estático, pero dudo que los compiladores lo capten.

+0

Eddie Edwards: simplemente pasando el puntero del objeto sobre el que desea que se ejecute. 'Entidad x; afterCreation (&x);) . – orlp

+0

+1, simple y al grano :) Resuelve el problema real, en lugar de lo que pregunta la pregunta (con un enfoque mucho más simple que SFINAE --Estoy asumiendo que nada en la función solo compilará ' Tipos derivados de Entity', es decir, no hay nada como 'entity-> getEntityName()' que no compilará para tipos derivados de Entity no) –

+0

Sorry nightcracker Retiré mis comentarios (y se aplicaron a su respuesta no editada) Creo que un gran cantidad de compiladores eliminará dynamic_cast ya que tiene pleno conocimiento del tipo de x. O, al menos, todo el conocimiento que necesita, suponiendo que la solución con plantilla pueda funcionar en absoluto. –

Cuestiones relacionadas