2013-06-04 13 views
7

Ich habe Probleme, statische Member-Funktion innerhalb der Klassenvorlage definiert zugreifen. Im TemplateTest.h Header-Datei definiert ich die primäre Klasse Template als:statische Member-Funktion innerhalb der Klassenvorlage Spezialisierung

#include<iostream> 

template<class T, class U> 
struct TemplateTest 
{ 
public: 
    void static invoke(); 
    /*{ 

     std::cout << "Should not be called" << std::endl; 

    }*/ 
}; 

Dann Quelle TemplateTester.cpp Datei ich eine Spezialisierung setzen:

#include "TemplateTest.h" 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue 

ich die Klasse explizit mit so Linker Entschlüssen instanziiert korrekt.

Im Treiber driver.cpp:

include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
    return 0; 
} 

Wenn ich die TemplateTest.cpp mit g ++ kompiliert generiert es die Objektdatei korrekt, aber wenn ich versuche, es dem Fahrer Klasse zu verknüpfen gibt es meine Linker-Fehler " undefinierter Verweis auf `TemplateTest :: invoke()"

Ich ging durch andere verwandte Postings wie this one, aber ich versuche nicht auf eine Funktionsvorlage zuzugreifen.

Jeder Hinweis wird sehr geschätzt.

+4

Verschieben Sie die Implementierung in die Headerdatei. Die Implementierungen der Vorlage müssen für alle TU sichtbar sein, die sie verwenden. –

Antwort

5

Sie haben Recht, dass das Objekt Datei, die Sie von TemplateTester.cpp erstellen ein Symbol für die Spezialisierung enthält, die Sie zur Verfügung gestellt. Dies ist der Fall, weil jede explizite Spezialisierung die Instanz instantiiert, und es ist doppelt so, weil Sie sogar eine explizite Instanziierung hinzugefügt haben (was eigentlich unnötig ist).

Jedoch, zu der Zeit, als driver.cpp kompiliert wird, weiß der Compiler nicht über die Spezialisierung, weil Sie nur TemplateTester.h einschließen, und die Spezialisierung wird dort nicht erwähnt. Also der Compiler instanziiert die Vorlage, natürlich nicht mit der spezialisierten Definition, so dass Sie Ihr Problem bekommen.

The Standard sagt (Kursiv von mir):

(§ 14.7.3/6) Wenn eine Vorlage, eine Mitgliedervorlage oder ein Mitglied einer Klassenvorlage explizit spezialisiert ist, dann muss diese Spezialisierung vor der ersten Verwendung dieser Spezialisierung deklariert werden, die eine implizite Instantiierung, , in jeder Übersetzungseinheit bewirken würde was eine solche Verwendung vorkommt; ist keine Diagnose erforderlich. Wenn das Programm keine Definition für eine explizite Spezialisierung bereitstellt und entweder die Spezialisierung in einer Weise verwendet wird, die eine implizite Instantiierung verursacht oder das Mitglied eine virtuelle Mitgliedsfunktion ist, ist das Programm schlecht ausgebildet, keine Diagnose erforderlich. Eine implizite Instanziierung wird niemals für eine explizite Spezialisierung generiert, die deklariert, aber nicht definiert ist. [...]

Sie müssen also beide machen, die Erklärung und die Definition der dem Compiler bekannt Spezialisierung, wenn es auf driver.cpp funktioniert. Der beste Weg, dies zu tun ist, indem Sie die gesamte Spezialisierung TemplateTester.h hinzufügen.

Beachten Sie, dass eine explizite Instanziierung nicht unbedingt erforderlich ist.

+1

Danke für die Erklärung @jogojapan. Dies ist eigentlich ein Prototyp der statischen Bibliothek, an der ich arbeite. Jetzt kann ich sehen, warum es scheitert Ich denke, ich kann die Definitionen verschieben, um den Compiler glücklich zu halten. – jazaman

3

Es gibt mehrere Probleme:

  • Sie brauchen nicht explizit vollständig spezialisierte Vorlage
  • instanziiert, wenn Sie Ihre statische Methode in der Kopfzeile setzen wollen, dann inline verwenden. Andernfalls erhalten Sie mehrere Instanzen und Linker Probleme
  • Vorlage Spezialisierungen, die Sie in die Kopfzeile und definieren Methoden in den Quelldateien
  • Wenn Sie nicht möchten, dass etwas in einer Vorlage aufgerufen werden, müssen Sie nicht definieren es. Sie erhalten Compiler-Fehler, und das bedeutet früher Fehler zu fangen.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 
template<> 
struct TemplateTest<int, bool> 
{ 
    inline static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

// main.cpp 
include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
} 

Eine andere Möglichkeit ist die Kopfzeile, zu ändern und die Quelldatei hinzuzufügen.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke(); 
}; 

// TemplateTest.cpp 
#include "TemplateTest.h" 
void TemplateTest<int, bool>::invoke() 
{ 
    std::cout << "invoke<int, bool>" << std::endl; 
} 
+0

Danke @ BЈovић Ich habe tatsächlich versucht, hier einen Prototyp zu entwickeln. Vielleicht sollte ich sie ausdrücklich erwähnen. Die Klassenvorlagen sind eigentlich Teil einer statischen Bibliothek und daher denke ich, dass ich die Instanziierung noch benötigen würde. Aber du hast recht, ich sollte keine Funktion innerhalb der Klasse definieren. Es sollte draußen gemacht werden. Ich werde das versuchen und sehen, ob es mein Problem löst. – jazaman

+0

@jazaman Nein, Sie müssen keine vollständig spezialisierten Vorlagen instanziieren, da sie wie normale (Nicht-Vorlagen-) Klassen sind. Wenn Sie Ihre Kopfzeile an mehreren Stellen einfügen, erhalten Sie Linker-Fehler. –

+0

nach dem Lesen der anderen Antwort verstehe ich, dass, wenn es vollständig spezialisiert Fall nicht mehr tun müssen. – jazaman

Verwandte Themen