2010-09-13 3 views
12

dachte ich, eine explizite Anfrage Instanziierung automatisch alle Basisklassenmitglieder auch instanziiert würde, aber ich bekomme einen linker error: unresolved external symbol "public: void Base<int>::foo(int)" beim Bau dieses Code Visual Studio 2008 oder 2010Explizite Instanziierungen von C++ - Klassenvorlagen instanziieren Abhängige Basisklassen?

Hinweis verwenden, um einen Anruf zu foo() innerhalb bar() zwingt den Compiler Hinzufügen instanziieren Base<int>::bar() und der Build ist erfolgreich, so scheint es, dass der Compiler über alle notwendigen Informationen verfügt, um foo() instanziieren.

Offensichtlich instanziieren Base<int> in source.cpp explizit das Instanziieren des Builds, aber es scheint albern, alle abhängigen Basisklassen explizit zu instanziieren, wenn eine abgeleitete Klasse explizit instanziiert wird.

Ist das normal? Ich konnte nicht finden, was der Standard zu diesem Thema sagt.

header.h

template<typename T> 
class Base { 
public: 
    void foo(); 
}; 

template<typename T> 
class Derived : public Base<T> { 
public: 
    void bar(); 
}; 

source.cpp

#include "header.h" 

template<typename T> 
void Base<T>::foo() { } 

template<typename T> 
void Derived<T>::bar() { 
    // this->foo(); // adding this forces instantiation of foo()??? 
} 

template class Derived<int>; 

main.cpp

#include "header.h" 

int main() { 
    Derived<int> d; 
    d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)" 
} 

Bearbeiten:

Es sieht aus wie der Standard sagt, nur Mitglieder einer Klasse werden durch eine explizite Klasseninstanziierung instanziiert, so dass der Linker-Fehler in meinem Beispiel gerechtfertigt ist.

beachten, dass eine Klasse von Klasse-Kopf definiert ist {Mitglied-Spezifikation} und „Die Element-Spezifikation in einer Klassendefinition deklariert die vollständige Reihe von Mitgliedern der Klasse, kann kein Mitglied andere Stelle hinzugefügt werden.“ So befinden sich Mitglieder nur zwischen den geschweiften Klammern {}, und Mitglieder der öffentlichen Basisklasse werden nicht Mitglieder der abgeleiteten Klasse, sie sind lediglich von der abgeleiteten Klasse oder von Objekten der abgeleiteten Klasse zugänglich.

Meine einzige verbleibende Frage ist, warum der Standard angibt, dass die explizite Instantiierung einer Klassenvorlage nur Mitglieder und nicht Mitglieder von Basisklassen instanziiert? Meine Vermutung ist, dass dies eine bessere Kontrolle dessen ermöglicht, was explizit wo instanziiert wird. Jemand, der explizite Vorlagenklasseninstanziierungen verwendet, würde höchstwahrscheinlich die Basisklassendefinitionen in einer anderen Datei als die abgeleiteten Klassendefinitionen haben und diese explizit separat instanziieren.

+0

Fügt ein expliziter Konstruktor für abgeleitete Triggerinstanziierung der Basisklasse hinzu? Ich vermute, dass der Compiler versucht, nicht mehr zu tun als nötig. Wenn Sie einen Konstruktor haben, könnte er erkennen, dass er auch Base erstellen muss, und das könnte ihn auslösen. Hast du auch gcc oder andere Compiler ausprobiert? –

+0

Das Hinzufügen eines Konstruktors mit oder ohne Argument und mit oder ohne Schlüsselwort "explizit" löst keine Instanziierung der Basisklasse foo() aus, aber ein Aufruf von foo() aus der abgeleiteten Elementleiste() löst die implizite Instanziierung aus. – JohnPS

Antwort

9

Die Norm sagt

Die explizite Instanziierung einer Klasse Template-Spezialisierung die Instanziierung aller seiner Mitglieder impliziert die zuvor nicht explizit in der Übersetzungseinheit spezialisiert, um die explizite Instanziierung enthält.

Mit anderen Worten, es wird nicht vorgeschrieben, dass Basisklassen wiederum explizit instanziiert werden. Es wird eine implizite Instantiierung von ihnen verursachen, die ihre Elementdefinitionen nicht im Voraus instanziiert.Es ist ein hässlicher Fehler in der Norm, ob ein Text, wenn er "Mitglied" bedeutet, "direkt" oder "geerbt" bedeutet, da dies oft für den, der den Standardtext geschrieben hat, "offensichtlich" zu sein scheint Einer, der es liest. C++ 0x hat einige Klarstellungen hinzugefügt (es hat auch einen Unterschied zwischen der expliziten Instanziierung Deklarationen und Definitionen, die C++ 03 nicht hat, aber selbst wenn ich das ignoriere, enthält der C++ 0x-Wortlaut einige Bits mehr Einsicht):

eine explizite Instanziierung, die eine Klasse Template-Spezialisierung Name ist auch eine explizite Instanziierung der gleichen Art (Erklärung oder de fi nition) jedes ihrer Mitglieder (ohne Mitglieder von der Basis Klassen geerbt), der hat bisher nicht ausdrücklich auf die Übersetzungseinheit spezialisiert, die die explizite Instanziierung enthält, außer wie nachstehend beschrieben. [Anmerkung: Zusätzlich wird es typischerweise eine explizite Instanziierung von bestimmten implementierungsabhängigen Daten über die Klasse sein. - Endnote]

+0

+1. Gibt es keine breitere pauschale Aussage, die sie treffen können, so dass sie sich nicht von Definition/Deklaration einer Klasse und all ihren statischen Mitgliedern unterscheiden lässt? Offenlassen, ob die V-Tabelle instanziiert ist, ist Hässlichkeit, die sie anerkennen. – Potatoswatter

+1

+1 Der Standard verwirrte mich durch die Verwendung von "Klassenvorlagenspezialisierung", um eine Entität zu bezeichnen, die durch "explizite Instantiierung" im Vergleich zur "expliziten Spezialisierung" unter Verwendung von Vorlage <> erzeugt wurde. Ich nehme an, dass das Nicht-Instanziieren von Basiselementen eine bessere Kontrolle dessen ermöglicht, was instanziiert wird und wohin es geht. Basismitglieder können in einer anderen Quelldatei als der abgeleiteten Klasse instanziiert werden. – JohnPS

+0

@Potatoswatter: Brauchen wir nicht nur die Deklaration der Basisklasse, um die Größe der Vtable der abgeleiteten Klasse während der Instantiierung der abgeleiteten Klasse zu bestimmen, und die Werte in ihrer Vtable werden vom Linker ausgefüllt? Wenn irgendeine aufgerufene Funktion in einer Übersetzungseinheit nicht instanziiert wird, wird ein Linkerfehler auftreten. – JohnPS

Verwandte Themen