2014-05-19 14 views
9

Diese Frage berücksichtigt explizite Instanziierung von Vorlagenklassen.Wie werden Basisvorlagenklassen explizit installiert?

Betrachten Sie eine Vorlagenklasse B<T>, die von einer anderen Vorlagenklasse A<T> abgeleitet wurde. Ich möchte B<T> explizit instanziieren, da seine Methoden aus dynamischer Verknüpfung aufgerufen werden sollen, also müssen die Methoden instanziiert werden, obwohl sie nicht in dem Code selbst aufgerufen werden. Natürlich werden auch Methoden, die von A<T> übernommen wurden, aufgerufen, also müssen sie ebenfalls instanziiert werden.

Es scheint, dass C++ nicht Instanciate Klassen Base, wenn explizit eine Template-Klasse Instanziierung, wie sie in dieser Frage gestellt: Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes? Beispiel:

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()!!! 

Natürlich, ich brauche auch alle Basisklassen instanziieren. Allerdings möchte ich den Client-Code damit nicht belasten, weil die Klassenhierarchie sehr tief sein kann. Betrachten Sie eine Klassenhierarchie mit 10 oder mehr Vorlagenklassen. Der Kunde sollte nicht dazu aufgefordert werden, 10 explizite Vorlagen zu schreiben. Das ist nicht nur viel Schreiben; es wird auch brechen, wenn ich Änderungen an der Klassenhierarchie einführe.

Stattdessen möchte ich irgendwie erreichen, dass, wann immer B<T> instanziiert ist, dann sind alle seine Basisklassen. Ich habe versucht, einfach die Basisklasse in B selbst wie folgt zu installieren:

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

Aber das kompiliert nicht. Gibt es andere Möglichkeiten, dies zu erreichen?

Antwort

2

Vielleicht nicht elegant, aber zumindest praktikabel: bietet einen Makro die Vorlage zu instanziiert und muss den Benutzer das Makro anstelle der manuellen Instanziierung verwenden:

// 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>; 

Und wenn Sie „verschmutzt“ die Klasse Schnittstelle bevorzugen Erzwingen der Verwendung eines Instanziierungsmakros: Fügen Sie ein protected-Element hinzu, das alle anderen Elementfunktionen der Vorlage und die Version in der Basisklasse aufruft. Beispiel:

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 

Update:

Alternative zu der zweiten Lösung: den Funktionszeiger aller Mitglieder nehmen und sie in eine temporäre Variable speichern:

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

Das Problem mit der zweiten Lösung ist, dass einige Methoden große Signaturen haben und es nicht einfach ist, Werte zu erzeugen, die den Methoden zugeführt werden. Die erste würde funktionieren, ist aber in der Tat hässlich :(. – gexicide

+0

Eine Variante der zweiten Lösung hinzugefügt, auch wenn dies ungefähr so ​​ausführlich und nicht wirklich erforderlich ist: Die Idee ist, dass 'instanziate()' nie wirklich ausgeführt wird. –

+0

Okay, dass Die Schnittstellen sind jedoch sehr groß, so dass die Aufzählung aller Methoden viel mehr Arbeit bedeutet als das Aufzählen aller Basisklassen, ich hoffe, dass es andere Wege gibt, aber danke für diese Antwort. – gexicide

Verwandte Themen