2012-03-30 22 views
5

Ho classe World che gestisce la creazione dell'oggetto ... Dopo la creazione chiama il metodo afterCreation e I l'oggetto creato è un tipo definito dall'utente derivato dall'entità (ad esempio MyEntity), Voglio chiamare addEntity. Io l'oggetto era qualcos'altro, non voglio fare niente. addEntity deve essere richiamato con adeguata T, perché genera ID univoci per ogni classe derivata eccCome specializzare template per tipo derivato dal particolare tipo

Ecco la mia soluzione:

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

} 

La mia domanda è - può essere fatto in modo migliore?

Come posso simulare il seguente codice senza ToType o simile?

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

template <typename T where T is derived from Entity> 
void afterCreation(){/*some specific stuff*/} 
  • "specializzati" nel titolo è solo quello di descrivere la mia intenzione, non c'è bisogno di risolvere il problema con il modello di specializzazione

risposta

3

Non sta andando a fare molto meglio, ma è possibile rimuovere un livello di indirezione utilizzando 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 
} 

Come funziona? Quando il compilatore trova la chiamata a afterCreation prova a determinare quale dei sovraccarichi è migliore, e per quello corrisponde ai tipi e tenta di eseguire la sostituzione. In entrambi i casi, il tipo corrispondente (dagli argomenti) e applica la sostituzione all'intera espressione. Il modello enable_if contiene un tipo interno type se il valore passato come primo argomento è true oppure non contiene tale tipo. Durante la sostituzione dei tipi, uno dei sovraccarichi produrrà una firma di funzione non valida (quella per cui la condizione è falsa) e verrà eliminata dall'insieme di candidati.

1

Si può fare questo con i puntatori polimorfici:

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

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

Anche se questo potrebbe non essere la soluzione migliore poiché questo ha un (piccolo) sovraccarico di runtime. Un compilatore molto intelligente potrebbe rimuovere questo sovraccarico attraverso l'analisi statica, ma dubito che i compilatori lo prenderanno in considerazione.

+0

Eddie Edwards: è sufficiente passare il puntatore dell'oggetto su cui si desidera che venga eseguito. 'Entità x; afterCreation (&x); '. – orlp

+0

+1, semplice e al punto :) Risolve il problema reale, piuttosto che la domanda (con un approccio molto più semplice di SFINAE - Sto assumendo che nulla nella funzione verrà compilato solo per' Tipi derivati ​​dall'entità, cioè non esiste nulla come 'entity-> getEntityName() 'che non riuscirà a compilare per tipi derivati ​​non Entity) –

+0

Scorri notturni scusi Ho ritirato i miei commenti (e si sono applicati alla tua risposta inedita) Penso che un molto del compilatore rimuoverà il dynamic_cast poiché ha piena conoscenza del tipo di x. O almeno la conoscenza di cui ha bisogno, supponendo che la soluzione basata su modelli possa funzionare del tutto. –

Problemi correlati