2009-07-10 4 views
36

Das hat mich in den letzten anderthalb Stunden verrückt gemacht. Ich weiß, es ist eine kleine Sache, aber ich kann nicht herausfinden, was falsch ist (die Tatsache, dass es an einem regnerischen Freitagnachmittag ist, hilft natürlich nicht).Undefinierter Referenzfehler für Template-Methode

Ich habe die folgende Klasse definiert, die aus einer Datei lesen Konfigurationsparameter halten und wird es mir von meinem Programm zugreifen können:

class VAConfig { 
    friend std::ostream& operator<<(std::ostream& lhs, const VAConfig& rhs); 

private: 
    VAConfig(); 
    static std::string  configFilename; 
    static VAConfig*  pConfigInstance; 
    static TiXmlDocument* pXmlDoc; 
    std::map<std::string, std::string> valueHash; 

public: 
    static VAConfig* getInstance(); 
    static void setConfigFileName(std::string& filename) { configFilename = filename; } 
    virtual ~VAConfig(); 

    void readParameterSet(std::string parameterGroupName); 
    template<typename T> T readParameter(const std::string parameterName); 
    template<typename T> T convert(const std::string& value); 
}; 

, wo die Methode convert() in VAConfig.cpp als

definiert ist
template <typename T> 
T VAConfig::convert(const std::string& value) 
{ 
    T t; 
    std::istringstream iss(value, std::istringstream::in); 
    iss >> t; 
    return t; 
} 

Alles ganz einfach. Aber wenn ich von meinem Hauptprogramm teste mit

int y = parameters->convert<int>("5"); 

Ich erhalte ein undefined reference to 'int VAConfig::convert<int>...' Übersetzungsfehler. Dito für readParameter().

Sah sich viele Vorlagen Tutorials aber konnte nicht herausfinden, dies aus. Irgendwelche Ideen?

+2

Eineinhalb Stunden ist nicht so schlimm ... es hat mich gestern um 3 getötet. –

Antwort

55

Templated Code-Implementierung nie in einer .cpp Datei sein sollte: Ihr Compiler hat sie zur gleichen Zeit zu sehen, wie sie den Code sehen, dass sie nennt (es sei denn, Sie explicit instantiation verwenden, um den Templat-Objekt-Code zu generieren, aber auch dann .cpp ist der falsche zu verwendende Dateityp).

Sie müssen die Implementierung entweder in die Header-Datei oder in eine Datei wie VAConfig.t.hpp und dann #include "VAConfig.t.hpp" verschieben, wenn Sie Vorlagenfunktionen verwenden.

+0

Danke Seth und Dominic, ich habe die Implementierungen in die Header-Datei verschoben und es hat funktioniert. Ich habe diesen Aspekt in keinem Tutorial gesehen, das ich gelesen habe. Also, warum muss der Compiler die Implementierung zu der gleichen Zeit sehen, in der er den Code sieht, der sie aufruft, d. H. Was macht die Templatfunktionen in dieser Hinsicht einzigartig? – recipriversexclusion

+2

Der Compiler muss die gesamte Vorlagendefinition zur Verfügung haben, wenn er instanziiert wird - damit er die Vorlagenparameter ersetzen und auswerten kann. Wenn Ihr Compiler dies unterstützt, können Sie Ihre Vorlage als "extern" deklarieren und sie so verwenden, wie Sie es für ein anderes Mitglied tun würden, auf Kosten zusätzlicher Link-Time-Arbeit. GCC unterstützt dies als Erweiterung. Es wird Teil des C++ 0x-Standards sein. – greyfade

+0

Es gibt Techniken, um Vorlagen wegzuhalten, nämlich Vorlagenspezialisierungen nach vorne zu deklarieren. -1 für "sollte nie" –

9

Wenn Sie die Implementierung der Template-Methoden (convert und readParameter) in die Header-Datei verschieben, sollte es funktionieren.

Der Compiler muss Zugriff auf die Implementierungen von Vorlagenfunktionen an den Stellen haben, an denen sie instanziiert werden.

5

Eine Template-Methode ist lediglich eine ... Vorlage für eine Methode. Die Template-Argumente müssen ausgefüllt werden, wenn die Methode "instanziiert" wird.

Es sollte möglich sein, einen Compiler zu erstellen, der mit der Deklaration einer Template-Methode zufrieden ist, und einen 'Template Compilation'-Schritt ausführen, um alle benötigten Instanzen der Template-Methode zu kompilieren.

Dies ist nicht der Fall für Microsofts Vc. Ich habe gehört, dass ein Kollege darüber murmelt, dass dies unter Unix der Fall ist.

Die meisten Compiler instanziieren die Template-Methode auf Anfrage, wo sie im Quellcode verwendet werden. Um die Methode zu instanziieren, muss der Compiler den Vorlagenfunktionskörper "sehen". Aus diesem Grund wird der Hauptteil meistens entweder in der Header-Datei oder in z.B. eine .h.cpp-Datei, die dann als letzte Zeile der .h-Datei enthalten ist.

+0

Was Sie beschreiben, ist eine "externe Vorlage". Es ist in der nächsten Version des C++ - Standards enthalten und wurde lange von GCC unterstützt (als Erweiterung). Visual C++ sollte es in der aktuellen Beta der nächsten Version unterstützen. – greyfade

+0

@greyfade: Danke! – xtofl

+0

.h.cpp oder .hpp? – Naveen