2014-05-19 10 views
9

Questa domanda sta prendendo in considerazione l'istanziazione esplicita delle classi di modelli.Come instanziare le classi del template di base esplicitamente?

Considerare una classe modello B<T> derivata da un'altra classe modello A<T>. Voglio istanicare esplicitamente B<T> perché i suoi metodi devono essere chiamati dal collegamento dinamico, quindi i metodi devono essere instanciati anche se non vengono chiamati nel codice stesso. Naturalmente, verranno chiamati anche i metodi ereditati da A<T>, quindi devono essere instanciati.

Sembra che C++ non classi base instanciate quando instanciating esplicitamente una classe template, come richiesto in questa domanda: Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes? Esempio:

template<typename T> 
class A{ void foo(){...} }; 

template<typename T> 
class B : public A<T> {} 

template class B<int>; // This will NOT instanciate A<int>::foo()!!! 

Naturalmente, ho anche bisogno di instanciate tutte le classi di base. Tuttavia, non voglio sovraccaricare il codice client con questo perché la gerarchia delle classi potrebbe essere molto profonda. Considera una gerarchia di classi che coinvolge 10 o più classi di modelli. Il cliente non dovrebbe essere invitato a scrivere 10 istanze di template esplicite. Questo non è solo un sacco di scrittura; si romperà anche quando introdurrò delle modifiche alla gerarchia delle classi.

Invece, voglio ottenere in qualche modo che ogni volta che B<T> è instanciato, quindi sono tutte le sue classi base. Ho provato semplicemente a instanciare la classe base in B in questo modo:

template<typename T> 
class B : public A<T> { 
    template class A<T>; // Does not compile! 
} 

Ma questo non viene compilato. Ci sono altri modi per ottenere questo?

risposta

2

Forse non elegante, ma almeno praticabile: fornire una macro per istanziare il modello e richiedere all'utente di utilizzare la macro in vece di esemplificazione manuale:

// in A.hpp 
#define INSTANTIATE_A(T) template class A<T>; 

// in B.hpp 
#define INSTANTIATE_B(T) \ 
    INSTANTIATE_A(T)  \ 
    template class B<T>; 

E se si preferisce "inquinare" l'interfaccia di classe per imporre l'uso di una macro di istanza: aggiungere un membro protected che chiama tutte le altre funzioni membro del modello e la versione nella classe base. Esempio:

template<typename T> 
class A 
{ 
    void foo() {...} 
protected: 
    void instantiate() { foo(); } 
}; 

template<typename T> 
class B : public A<T> 
{ 
    void bar() {...} 
protected: 
    void instantiate() { A<T>::instantiate(); bar(); } 
}; 

template class B<int>; // Now works as expected 

Aggiornamento:

alternativa alla seconda soluzione: prendere il puntatore a funzione di tutti i membri e salvarli in una variabile temporanea:

template<typename T> 
class A 
{ 
    void foo() {...} 
protected: 
    void instantiate() { void (A::*p)() = &A::foo; } 
}; 

template<typename T> 
class B : public A<T> 
{ 
    void bar() {...} 
protected: 
    void instantiate() { A<T>::instantiate(); void (B::*p)() = &B::foo; } 
}; 
+0

Il problema con la seconda soluzione è che alcuni metodi hanno grandi firme e non è facile produrre valori per alimentare i metodi. Il primo funzionerebbe ma è davvero brutto :(. – gexicide

+0

Aggiunta una variante della seconda soluzione, anche se si tratta di una cosa prolissa e non realmente richiesta: l'idea è che 'instantiate()' non viene mai realmente eseguito. –

+0

Ok, che è più fattibile, ma comunque le interfacce sono grandi, quindi enumerare tutti i metodi è molto più lavoro di enumerare tutte le classi base. Spero ci siano altri modi per uscire da questo, ma grazie per questa risposta comunque. – gexicide

Problemi correlati