Ich hätte gerne ein besseres Verständnis darüber, wann der Compiler eine Memberfunktionsvorlage implizit instantiiert.
Betrachten Sie das folgende Beispiel:
%Vor% Beim Kompilieren mit [g++|clang++] -c example.cpp
implizit erzeugen sowohl GCC als auch clang implizit die Funktionsvorlage Child::bar<double>
. Folgende scheinbar geringfügige Änderungen verhindern dies jedoch:
foo
nicht virtuell Child
wird nicht von Parent
übernommen
baz
baz
nicht virtuell baz
mit der Deklaration in der Kopfzeile Gibt es eine einigermaßen knappe Erklärung dafür, wann eine implizite Instanziierung stattfindet oder muss ich eine Kopie des Standards durchgehen? Ich habe SO nach anderen Fragen zur impliziten Instanziierung gesucht, aber nicht viel gefunden. Der nächste, den ich gefunden habe, war diese Frage , aber es geht um virtuelle Funktionen in Klassenvorlagen (keine Memberfunktionsvorlagen).
Um es klar zu sagen: Ich verstehe, dass dieses Problem vermieden werden kann, indem entweder die Definition in die Kopfzeile eingefügt wird oder die benötigten Vorlagen explizit instanziiert werden. Dies ist nur als ein Punkt der Neugierde entstanden, als ich untersucht habe, warum eine Klasse (deren explizite Instanziierungen ich versehentlich weggelassen habe) nichtsdestoweniger glücklich zusammengestellt und verknüpft wurde.
Ich habe Ihren Code in Visual Studio 2013 (child.h und child.cpp) eingefügt und Folgendes versucht:
%Vor%Dies erzeugt einen ungelösten externen Fehler, der anzeigt, dass keine "implizite Instantiierung" auftritt. In diesem Fall gibt es einen deutlichen Unterschied zwischen Visual Studio und G ++. Dies wurde behoben, indem der Code von Child :: foo in die Datei child.cpp verschoben wurde.
Daher lautet die kurze Antwort: Was Sie gerade erleben, ist zu einem großen Teil compilerspezifisch und für Portabilität sollten Sie sich nicht auf dieses Verhalten verlassen. Nach C ++ - Standards ist es am sichersten, Ihre Vorlagendefinitionen entweder in eine .h (oder .hpp) -Datei zu schreiben oder die Vorlagen nach Bedarf explizit zu instanziieren. Jede andere Möglichkeit, dies zu handhaben, wird wahrscheinlich einige Compiler einbrechen.
Um das Verhalten von Visual Studio näher zu verstehen, werfen Sie einen Blick darauf:
Was gesagt wird, ist, dass jede in der Definition der Klasse definierte Funktion implizit inline ist. Der Compiler kann die Instanziierung einer Inline-Funktion verzögern, wenn er dies wünscht. Dies bedeutet, dass beim Kompilieren von child.obj Child :: foo (d) niemals erzeugt wird, was wiederum bedeuten würde, dass bar niemals instanziiert wird, so dass dies das Kompilierproblem während der Verknüpfungsstufe verursacht. Warum Visual Studio dies unter Berücksichtigung von foo (double) tatsächlich tun kann, ist technisch gesehen eine virtuelle Funktion in der Tat seltsam, aber es scheint, dass Visual Studio die Instanziierung von foo () für später zurücklässt, wenn Child verwendet wird. Also zum Beispiel:
%Vor%Erzeugt auch ein Problem, da der Compiler zu diesem Zeitpunkt versucht, Child :: foo (double) zu erstellen, und dies wegen der fehlenden Template-Definition nicht möglich ist.
Aus Ihren Ergebnissen wird angenommen, dass GCC sofort Inline-Funktionen instanziiert, wenn sie virtuell sind.
Das Verhalten, das Sie erleben, ist eine Kombination von Dingen:
Weitere Informationen finden Sie in den folgenden Fragen:
Also:
Ich habe mich entschieden, Ihre spezifischen Fragen nicht im Detail zu beantworten, da meine Nachforschungen darauf hindeuten, dass Ihre Codearbeit umständlich ist und auf dieses Verhalten nicht Verlass ist.