Mehrere Definitionen einer Funktionsvorlage
Frage
Angenommen, eine Header-Datei eine Funktion Vorlage definiert. Nehmen wir nun an zwei Implementierungsdateien diesen Header #include
, und jeder von ihnen hat einen Aufruf an die Funktion Vorlage. In beiden Implementierungsdateien wird die Funktion Vorlage mit dem gleichen Typ instanziiert.
// header.hh
template <typename T>
void f(const T& o)
{
// ...
}
// impl1.cc
#include "header.hh"
void fimpl1()
{
f(42);
}
// impl2.cc
#include "header.hh"
void fimpl2()
{
f(24);
}
kann man erwarten, dass der Linker würde über mehrere Definitionen von f()
beschweren. Insbesondere dann, wenn f()
keine Vorlage wäre dann in der Tat, dass der Fall wäre.
- Wie kommt es, den Linker beschwert sich nicht über mehrere Definitionen von
f()
? - Ist es in der Norm festgelegt, dass der Linker diese Situation anmutig behandeln müssen? Mit anderen Worten, kann ich auf Programme ähnlich wie oben zählen immer zu kompilieren und verknüpfen?
- Wenn der Linker klug genug sein kann, eine Reihe von Funktionsvorlage instantiations eindeutig zu machen, warum kann es das gleiche für reguläre Funktionen nicht tun, da sie identisch sind, wie der Fall für instanzierte Funktionsschablonen ist?
Lösung
Um C ++ zu unterstützen, der Linker intelligent genug, um zu erkennen, dass sie alle die gleiche Funktion und wirft alle bis auf einen.
EDIT: Klarstellung: Der Linker nicht Funktion Inhalte vergleichen und festzustellen, dass sie gleich sind. Templated Funktionen sind als solche gekennzeichnet und der Linker erkennt an, dass sie die gleichen Signaturen haben.
Andere Tipps
Die Gnu C ++ Compiler Anleitung hat eine gute Diskussion dieser . Ein Auszug:
C ++ Templates sind die erste Sprache Funktion mehr Intelligenz erfordern aus der Umgebung als man in der Regel findet auf einem UNIX-System. irgendwie ist der Compiler und Linker müssen sicherstellen, dass jede Vorlageninstanz auftritt genau einmal, wenn es in der ausführbaren Datei erforderlich ist, und gar nicht anders. Es gibt zwei grundlegende Ansätze für diese Problem, das als das bezeichnet werden Borland-Modell und das Cfront Modell.
Borland Modell
Borland C ++ löste das Template Instanziierung Problem durch die Zugabe von Code-Äquivalent von gemeinsamen Blöcken ihre Linker; der Compiler aussendet Vorlageninstanzen in jeder Übersetzung Einheit, die sie, und der Linker verwendet kollabiert sie zusammen. Der Vorteil nur dieses Modells ist, dass der Linker muss die Objektdateien betrachten sich; gibt es keine externe Komplexität zu befürchten. Diese Nachteil ist, dass die Kompilierung wird, weil der Template-Code erhöht kompiliert wiederholt wird. Code geschrieben für dieses Modell dazu neigt, umfassen Definitionen aller Vorlagen in der Header-Datei muss, da sie sein gesehen instanziiert werden.
Cfront Modell
Die AT & T C ++ Übersetzer, Cfront, löste die Template-Instantiierung Problem durch die Vorstellung von einer Schaffung Template-Repository, ein automatisch gepflegt Ort, an dem Template Instanzen gespeichert. Eine modernere Version des Repository arbeitet als folgt: Da die einzelnen Objektdateien gebaut werden, legt der Compiler jede Template-Definitionen und instantiations begegnet in der Repository. Bei Link Zeitpunkt der Link Wrapper fügt in den Objekten in der Repository und stellt alle benötigten Instanzen, die nicht zuvor waren ausgesendet. Die Vorteile dieses Modells sind optimale Übersetzungsgeschwindigkeit und die Fähigkeit, das System Linker zu verwenden; Borland Modell einer implementieren Compiler-Anbieter muss auch ersetzen der Linker. Die Nachteile sind, in beträchtlichem Ausmaß der Komplexität erhöht und damit Fehlerpotenzial; für einige Code dies kann genauso transparent sein, aber In der Praxis kann es sehr schwierig sein, mehrere Programme in einem bauen Verzeichnis und ein Programm in mehreren Verzeichnisse. Code für diese geschrieben Modell neigt dazu, getrennte Definitionen nicht-inline Element Vorlagen in eine separate Datei, die sein sollte separat zusammengestellt.
Wenn Sie mit GNU ld Version 2.8 oder verwendet später auf einem System, wie ELF GNU / Linux oder Solaris 2, oder auf Microsoft Windows, G ++ unterstützt die Borland-Modell. Auf anderen Systemen G ++ weder automatisches Modell implementiert.
Dies ist mehr oder weniger ein Sonderfall nur für Vorlagen.
Der Compiler erzeugt nur die Vorlage instantiations, die tatsächlich verwendet werden. Da es keine Kontrolle darüber, welcher Code hat, wird von anderen Quelldateien erzeugt wird, hat es den Template-Code zu erzeugen, einmal für jede Datei, um sicherzustellen, dass das Verfahren überhaupt erzeugt wird.
Da es schwierig ist, diese zu lösen (der Standard hat eine extern
Schlüsselwort für Vorlagen, aber g ++ nicht implementiert es nicht) der Linker einfach akzeptiert die mehrere Definitionen.