Ihr Beispiel ist korrekt, aber nicht sehr portabel. Es gibt auch eine etwas sauberere Syntax, die verwendet werden kann (wie von @namespace-sid und anderen angemerkt).
Angenommen, die templatärisierte Klasse ist Teil einer Bibliothek, die gemeinsam genutzt werden soll...
Sollten andere Versionen der templatärisierten Klasse kompiliert werden?
Erwartet der Bibliotheksverwalter alle möglichen templatärisierten Verwendungen der Klasse vorab?
Ein alternativer Ansatz
Fügen Sie eine dritte Datei hinzu, die die Template-Implementierungs-/Instantiierungsdatei in Ihren Quellen darstellt.
lib/foo.hpp
- aus der Bibliothek
#pragma once
template
class foo {
public:
void bar(const T&);
};
lib/foo.cpp
- das direkte Kompilieren dieser Datei verschwendet nur Kompilierzeit
// Hier Include-Guard einfügen, nur zur Sicherheit
#pragma once
#include "foo.hpp"
template
void foo::bar(const T& arg) {
// Irgendetwas mit `arg` machen
}
foo.MyType.cpp
- bei Verwendung der Bibliothek, explizite Template-Instantiierung von foo
// In Betracht ziehen, einen "Anti-Guard" hinzuzufügen, um sicherzustellen, dass er nicht in anderen Übersetzungseinheiten enthalten ist
#if __INCLUDE_LEVEL__
#error "Diese Datei nicht einfügen"
#endif
// Ja, wir fügen die .cpp-Datei ein
#include
#include "MyType.hpp"
template class foo;
Organisieren Sie Ihre Implementierungen wie gewünscht:
- Alle Implementierungen in einer Datei
- Mehrere Implementierungsdateien, eine für jeden Typ
- Eine Implementierungsdatei für jede Gruppe von Typen
Warum??
Dieses Setup sollte die Kompilierzeiten reduzieren, insbesondere für stark genutzten komplizierten templatärisierten Code, da Sie nicht die gleiche Headerdatei in jeder Übersetzungseinheit neu kompilieren. Es ermöglicht auch eine bessere Erkennung, welcher Code neu kompiliert werden muss, von Compilern und Build-Skripten, was die inkrementelle Build-Belastung verringert.
Beispielanwendungen
foo.MyType.hpp
- muss über die öffentliche Schnittstelle von foo
informiert sein, aber nicht über .cpp
-Quellen
#pragma once
#include
#include "MyType.hpp"
// `temp` deklarieren. Muss `foo.cpp` nicht einbeziehen
extern foo temp;
examples.cpp
- kann auf lokale Deklaration verweisen, muss aber auch foo
nicht neu kompilieren
#include "foo.MyType.hpp"
MyType instance;
// `temp` definieren. Muss `foo.cpp` nicht einbeziehen
foo temp;
void example_1() {
// `temp` verwenden
temp.bar(instance);
}
void example_2() {
// Funktion lokale Instanz
foo temp2;
// Templatärisierte Bibliotheksfunktion verwenden
temp2.bar(instance);
}
error.cpp
- ein Beispiel, das mit reinen Header-Templates funktionieren würde, aber hier nicht funktioniert
#include
// Verursacht Kompilierfehler zur Linkzeit, da wir nie die explizite Instantiierung hatten:
// template class foo;
// Der GCC-Linker gibt einen Fehler: "undefined reference to `foo::bar()'"
foo nonExplicitlyInstantiatedTemplate;
void linkerError() {
nonExplicitlyInstantiatedTemplate.bar();
}
Anmerkung: Die meisten Compiler/Linter/Code-Helfer erkennen das nicht als Fehler, da gemäß dem C++-Standard kein Fehler vorliegt. Aber wenn Sie diese Übersetzungseinheit in eine vollständige ausführbare Datei einbinden, wird der Linker keine definierte Version von foo
finden.
Alternativer Ansatz von: https://stackoverflow.com/a/495056/4612476
30 Stimmen
Ich hatte keine Ahnung, dass dies möglich war - ein interessanter Trick! Es hätte bei einigen aktuellen Aufgaben erheblich geholfen, dies zu wissen - Prost!
107 Stimmen
Das Ding, das mich verwirrt, ist die Verwendung von
do
als Kennung :p0 Stimmen
Ich habe etwas Ähnliches mit GCC gemacht, aber ich forsche immer noch.
27 Stimmen
Dies ist kein "Hack", sondern eine Vorwärtsdeklaration. Dies hat seinen Platz im Standard der Sprache; daher ist es in jedem standardkonformen Compiler erlaubt.
1 Stimmen
Was ist, wenn Sie Dutzende von Methoden haben? Können Sie einfach
template class foo;template class foo;
am Ende der .cpp-Datei machen?0 Stimmen
Verwandt: stackoverflow.com/questions/495021/…
0 Stimmen
Bitte korrigiere mich, wenn ich falsch liege, @AhmetIpkin. Ich glaube, das nennt man Template-Spezialisierung.
0 Stimmen
Ich mag es wirklich, Vorlageninstanzdefinitionen in der cpp zu speichern, weil es allen mitteilt, welche Implementierungen verwendet werden.