C ++ Implizite Instanziierung von Memberfunktionsvorlagen

8

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:

  • Making foo nicht virtuell
  • % Child wird nicht von Parent übernommen
  • Entfernen von baz
  • Making baz nicht virtuell
  • Definition von 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.

    
Tom 23.01.2015, 16:14
quelle

1 Antwort

2

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:

  1. Wie Compiler implizite Inline-Funktionen handhaben
  2. Wie virtuelle Tabellen für virtuelle Funktionen erstellt werden
  3. Und wenn der Compiler die virtuellen Memberfunktionen instanziieren muss.

Weitere Informationen finden Sie in den folgenden Fragen:

Also:

  • Es scheint, dass der Compiler das Instanziieren von Inline-Funktionen bis zur Verwendung verzögern und dann entscheiden kann, ob er sie "inline" einfügen oder eine separate Funktion erstellen möchte.
  • Bis zu dem Zeitpunkt, an dem eine Klasse verwendet wird, muss der Compiler die Instanziierung aller für das Objekt
  • erforderlichen Objekte nicht abschließen
  • Tatsächlich wird der Compiler während der Optimierung selbst beim Erstellen eines Objekts nicht alles im Code für die Klasse ready definiert haben.

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.

    
Heinrich du Toit 20.02.2015 07:43
quelle

Tags und Links