2009-03-17 10 views
3

ich eine Bibliothek verwende, die fast ausschließlich aus Templat Klassen und Funktionen in Header-Dateien, wie folgt zusammen:Klassendefinitionen automatisch von Deklarationen trennen?

// foo.h 
template<class T> 
class Foo { 
    Foo(){} 
    void computeXYZ() { /* heavy code */ } 
}; 
template<class T> 
void processFoo(const Foo<T>& foo) { /* more heavy code */ } 

Nun ist dies schlecht, weil kompilieren Zeiten sind unerträglich wenn ich gehören einer dieser Header Dateien (und tatsächlich schließe ich viele von ihnen in jede meiner Kompilierungseinheiten ein).

Da als Template-Parameter ich nur ein oder zwei Arten verwenden sowieso Ich plane, für jede Bibliothek Header-Datei zu erstellen, eine Datei, die nur Erklärungen, ohne die schwere Code enthält, wie folgt aus:

// NEW: fwd-foo.h 
template<class T> 
class Foo { 
    Foo(); 
    void computeXYZ(); 
}; 
template<class T> 
void processFoo(const Foo<T>& foo); 

Und dann eine Datei, die alle Instanziierungen erstellt, die ich brauche. Diese Datei kann separat einmal kompiliert und für alle:

// NEW: foo.cpp 
#include "foo.h" 
template class Foo<int>; 
template class Foo<double>; 
template void processFoo(const Foo<int>& foo); 
template void processFoo(const Foo<double>& foo); 

Jetzt kann ich nur fwd-foo.h in meinem Code enthalten und haben kurze Zeiten kompilieren. Ich werde am Ende gegen foo.o verknüpfen.

Der Nachteil ist natürlich, dass ich diese neuen fwd-foo.h und foo.cpp Dateien selbst erstellen muss. Und natürlich ist es ein Wartungsproblem: Wenn eine neue Bibliotheksversion veröffentlicht wird, muss ich sie an diese neue Version anpassen. Gibt es noch andere Nachteile?

Und meine Hauptfrage ist:

Gibt es eine Chance, dass ich diese neue Dateien erstellen kann, insbesondere fwd-foo.h, automatisch von den ursprünglichen foo.h? Ich muss dies für viele Bibliotheks-Header-Dateien tun (vielleicht 20 oder so), und eine automatische Lösung wäre am besten, wenn eine neue Bibliotheksversion veröffentlicht wird, und ich muss dies mit der neuen Version wiederholen. Gibt es Werkzeuge für diese Aufgabe?

EDIT:

Zusätzliche Frage: Wie kann die neu unterstützten extern Stichwort helfen Sie mir in diesem Fall?

Antwort

4

Wir lzz verwenden, die eine einzelne Datei in einen separaten Header und Übersetzungseinheit teilt aus . Standardmäßig werden die Vorlagendefinitionen normalerweise auch in die Kopfzeile eingefügt. Sie können jedoch angeben, dass dies nicht der Fall sein soll.

Um Ihnen zu zeigen, wie Sie es betrachten die folgenden verwenden könnte:

// t.cc 
#include "b.h" 
#include "c.h" 

template <typename T> 
class A { 
    void foo() { 
    C c; 
    c.foo(); 
    b.foo(); 
    } 
    B b; 
} 

Nehmen Sie die obige Datei und Datei zu ‚t.lzz‘ kopieren. Legen Sie alle # include Richtlinien in separate $ hdr und $ src Blöcke nach Bedarf:

// t.lzz 
$hdr 
#include "b.h" 
$end 

$src 
#include "c.h" 
$end 

template <typename T> 
class A { 
    void foo() { 
    C c; 
    c.foo(); 
    b.foo(); 
    } 
    B b; 
} 

nun endlich laufen LZZ über die Datei angeben, dass sie die Vorlage Definitionen in der Quelldatei platziert. Sie können zu diesem Zweck entweder ein $ Pragma in der Quelldatei verwenden, oder Sie können die Befehlszeilenoption „-ts“ verwenden:

Das in den folgenden Dateien führen erzeugt wird:

// t.h 
// 

#ifndef LZZ_t_h 
#define LZZ_t_h 
#include "b.h" 
#undef LZZ_INLINE 
#ifdef LZZ_ENABLE_INLINE 
#define LZZ_INLINE inline 
#else 
#define LZZ_INLINE  
#endif 
template <typename T> 
class A 
{ 
    void foo(); 
    B b; 
}; 
#undef LZZ_INLINE 
#endif 

Und:

Sie können diese dann durch einige grep/sed-Befehle ausführen, um die LZZ-Hilfsmakros zu entfernen.

+0

Das scheint genau das zu sein, was ich gesucht habe. Obwohl ich jetzt irgendwie müde bin, es tatsächlich zu benutzen ... – Frank

-1

C++ 0x wird Ihre Probleme bei der Kompilierung mit externen Vorlagen beheben. Ich weiß jedoch nicht, wie man automatisch das macht, was man verlangt.

+0

Wie funktioniert das? Ich muss die Deklarationen immer noch von den Definitionen trennen, nein? – Frank

+0

'extern' wird nicht mit Kompilierzeiten helfen, es beschränkt nur, was instanziiert wird, wenn eine implizite Instanziierung auftritt. –

1

Verwenden Sie vorkompilierte Header. Ich weiß, dass GCC und MSVC diese Funktion unterstützen. Die Verwendung ist jedoch für den Verkäufer spezifisch.

1

Ich habe seit einiger Zeit an dem gleichen Problem gearbeitet. In der von Ihnen vorgeschlagenen Lösung definieren Sie Ihre Vorlagenklassen zweimal. Es wird in Ordnung sein, wenn es die gleichen Dinge (in der gleichen Reihenfolge) definiert, aber Sie werden früher oder später Probleme haben.

Was ich habe, ist, das Problem anders herum zu betrachten. Solange Sie nicht auf Ihre Implementierung spezialisiert sind, funktioniert es ordnungsgemäß.

Es verwendet zwei Makros, die Template-Argumente in der Implementierungsdatei aktualisieren müssen (Vorsicht, wenn Sie der Klasse Standard-Template-Argumente hinzufügen möchten).

// foo.h 
#define FOO_TEMPLATE template<typename T> 
#define FOO_CLASS Foo<T> 

FOO_TEMPLATE 
class Foo { 
    Foo(); 
    void computeXYZ(); 
}; 

// foo_impl.h 
#include "foo.h" 
FOO_TEMPLATE 
FOO_CLASS::Foo(){} 

FOO_TEMPLATE 
void FOO_CLASS::computeXYZ() { /* heavy code */ } 

Auf diese Weise Sie im Wesentlichen auf die gleiche Weise mit Nicht-Template-Klassen arbeiten (Sie können mit Template-Funktionen, natürlich das Gleiche tun).

EDIT: über das Schlüsselwort extern in C++ 0x

Ich glaube, das Schlüsselwort extern in C++ 0x helfen, aber es wird nicht alles auf magische Weise lösen!

Von this article,

Extern Vorlagen

Jedes Modul, das eine Vorlage instanziiert im Wesentlichen eine Kopie es in dem Code-Objekt erstellt. Dann ist es bis an den Linker aller von dem redundanten Objektcode in der allerletzten Bühne zu verfügen, damit den kritischen edit-kompilieren-Link Zyklus zu verlangsamen, die einen Programmierers Tag (oder manchmal Wachträume) bildet. Um diese Objektcode-Speicherbereinigung kurzzuschließen, hat eine Anzahl von Compiler-Anbietern bereits ein externes Schlüsselwort implementiert, das vor Vorlagen gehen kann. Dies ist ein Fall der Standardisierung Kodifizierung bestehenden Industrie Praxis (Wortspiel beabsichtigt). In der Praxis ist dies umgesetzt durch eine Mitteilung an den Compiler grundsätzlich „nicht instanziiert dieses hier“ zu senden:

extern template class std::vector;