Klassen-Methoden Template -> Linker-Fehler
-
Hallo!
Ich versuche gerade eines meiner ersten Templates umzusetzen und stoße gleich
auf einen Fehler. Ich möchte, dass eine Member-Funktion einer Klasse für
verschiedene Typen nutzbar ist.So hab ich das umgesetzt:
class LevelParser { public: template <class T> T GetAttributeValue(string& attribute, string& tag, string parent=""); [...]
template <class T> T LevelParser::GetAttributeValue(string& attribute, string& tag, string parent) { [...] }
Beim Aufruf via:
LevelParser levelParser; levelParser.GetAttributeValue<double>(string("PatchLength"), string("value"));
bekomm ich aber den Fehler:
Nicht aufgeloestes externes Symbol "public: double __thiscall FDX::LevelParser::GetAttributeValue<double>(class std::basic_string...
Kann mir da einer auf die Sprünge helfen?
MfG,
EnERgYzEr
-
das ist dein problem:
T GetAttributeValue(string& attribute, string& tag, string parent="");
wenn der andere teil der methode in einer cpp ist, gibts einenf ehler, da dies kaum ein compiler unterstützt
-
Da hätte ich ja ewig weitersuchen können...
D.h. ich muss die ganze Methode in meiner Header-Datei definieren? Tritt dieses
Problem nur zusammen mit Klassen-Methoden auf oder auch bei normalen Funktionen?BTW: Ich nutze VS C++.NET 2002 Std.
-
Nur die template-funktionen!
-
Aber die Methode ist kein 2-Zeiler sondern hat schon so ihre 20 Zeilen. Das
sieht nicht wirklich schön aus, wenn das in der Header-Datei ist.
-
Es muss aber halt nun mal so sein! (Was würdest du nur zu meinen Projekten sagen! Augenkrebs würdest du bekommen! Ich benutze fast nur Template-Funktionen, und 100 Zeilen sind keine Seltenheit! Allgemein ist das Verhältnis header/cpp in meine Projekten so ungefähr 10/1
)
-
ness schrieb:
Es muss aber halt nun mal so sein! (Was würdest du nur zu meinen Projekten sagen! Augenkrebs würdest du bekommen! Ich benutze fast nur Template-Funktionen, und 100 Zeilen sind keine Seltenheit! Allgemein ist das Verhältnis header/cpp in meine Projekten so ungefähr 10/1
)
100 zeiler? bitte gewöhn dir einen andeen coding style an
-
EnERgYzEr schrieb:
Aber die Methode ist kein 2-Zeiler sondern hat schon so ihre 20 Zeilen. Das
sieht nicht wirklich schön aus, wenn das in der Header-Datei ist.Dann schreib doch die Implementation einfach in eine eigene Datei (z.B. foo.inl) und inkludiere selbige als letztes im Header. Alternativ kannst du dich ja auch mal mit dem Thema explizite Instanziierung beschäftigen.
-
HumeSikkins schrieb:
EnERgYzEr schrieb:
Aber die Methode ist kein 2-Zeiler sondern hat schon so ihre 20 Zeilen. Das
sieht nicht wirklich schön aus, wenn das in der Header-Datei ist.Dann schreib doch die Implementation einfach in eine eigene Datei (z.B. foo.inl) und inkludiere selbige als letztes im Header. Alternativ kannst du dich ja auch mal mit dem Thema explizite Instanziierung beschäftigen.
Explizite Instanziierung? Das bedeutet doch nur, dass man bei der Nutzung eines
Templates explizit angibt, welchen Typ man haben möchte. Wie würde mir das bei
meinem Problem helfen? Sorry, aber ich bin gerade erst am Anfang, was die
Template-Programmierung angeht.Das include-Verfahren wirkt auf mich noch unsauberer. Ich hab jetzt in den
sauren Apfel gebissen und die Derfinition in die Header-Datei geschrieben.Ist denn die Trennung von Definition und Deklaration im Standard vorgesehen?
Wenn ja, kann man ja noch auf neue Compiler hoffen.
-
EnERgYzEr schrieb:
[
Explizite Instanziierung? Das bedeutet doch nur, dass man bei der Nutzung eines
Templates explizit angibt, welchen Typ man haben möchte.Das bedeutet, dass man die *vollständige* Instanziierung eines Templates für einen bestimmten Typen erzwingt. Erreichen tut man eine explizite Instanziierung über eine "explicit instantiation directive" der Form:
template class Foo<Param>;
In der einfachsten Variante kann man mittels dieser Technik seperate Übersetzung von Templates wie folgt erreichen:
Für jede Template-Klasse Foo schreibt man drei Dateien:a) Foo.h -> Enthält die Klassendefinition von Foo b) Foo_impl.h -> Enthält die Implementation c) Foo_instantiate.cpp -> Enthält explizite Instanziierungen für alle benötigeten Typen.
Foo_instantiate inkludiert Foo.h und Foo_impl.h.
Benutzercode hingegen inkludiert immer nur Foo.h und linkt gegen Foo_instantiate.o, kann die Existenz von Foo_impl.h aber ignorieren.Eine etwas leistungsfähigere Technik findest du hier erklärt:
http://www.cuj.com/documents/s=8683/cuj0310niebler/Das include-Verfahren wirkt auf mich noch unsauberer.
Das ist allerdings ein reines Wahrnehmungsproblem deinerseits, dass nicht auf technischen Gründen basiert.
Ist denn die Trennung von Definition und Deklaration im Standard vorgesehen?
Der Standard spezifiziert für Templates sowohl ein "inclusion"- als auch ein seperates-Übersetzungsmodell. Das "inclusion"-Modell ist das was heutzutage nahezu überall benutzt wird (das mit der Definition der Methoden in jeder ÜE). Das seperate Übersetzungsmodell ist bisher hautpsächlich theoretischer Natur. Es angelehnt an das seperate Übersetzungsmodell von normalen Klassen, ist im Detail aber vollständig anders und wird über das Schlüsselwort export realisiert, dass derzeit nur von einem Compiler unterstützt wird. Die Sinnhaftigkeit dieses Modells wird nach wie vor bezweifelt. Ob es sich wirklich lohnt und in welcher Form es sich wann tatsächlich mal durchsetzt steht heute noch vollständig in den Sternen.
-
@energyzer extern ist dafür vorgesehen, aber nur der comeau unterstützt dies-.-
-
otze schrieb:
@energyzer extern ist dafür vorgesehen, aber nur der comeau unterstützt dies-.-
Nein. extern ist wieder etwas anderes.