2017-07-26 2 views
0

Ich versuche, externe Vorlagen zu verstehen, aber ich kann es nicht funktionieren. Mein Ziel ist es, einige Instanziierungen zu erstellen, wenn Foo<> in einer separaten Kompiliereinheit, um Kompilierungszeit zu speichern. In meiner Codebasis ist das Template-Argument ein enum class, so dass ich in der Theorie alle Instanziierungen in einer Kompilierungseinheit kompilieren und mit dem Rest des Projekts verknüpfen kann.Externe Vorlagen in C++ zu verstehen

Hier ist ein kleines Beispiel, das ich komme mit:

//Foo.hpp 
#pragma once 

template <class T> 
struct Foo { 
    Foo(); 
    ~Foo(); 
}; 

extern template struct Foo<int>; 

//Foo.cpp 
#include "Foo.hpp" 

template struct Foo<int>; 

//main.cpp 
#include <iostream> 

#include "Foo.hpp" 

int main(int argc, char **argv) { 
    Foo<int> foo; 

    return 0; 
} 

Um Kompilation i eine Make-Datei verwendet, die zu dieser läuft darauf hinaus:

g++ -c ../Foo.cpp ../main.cpp 
g++ Foo.o main.o 

Der Ausgang I mit gcc erhalten 7.1.1 und im Grunde das gleiche mit Klirren 4.0.1 ist:

main.o: In function `main': 
main.cpp:(.text+0x27): undefined reference to `Foo<int>::Foo()' 
main.cpp:(.text+0x38): undefined reference to `Foo<int>::~Foo()' 

Meine Hauptfrage ist, warum ist Foo<int>::Foo() und Foo<int>::~Foo() nicht in Foo.o zusammengestellt?

+1

Weil Sie dem Compiler absolut nichts geliefert haben, um ihm mitzuteilen, was der Konstruktor und der Destruktor tun. Fügen sie zwei Zahlen hinzu? Subtrahieren Sie zwei Zahlen? Zählen Sie die Anzahl der Wörter in "Krieg und Frieden"? Zählen Sie die Anzahl der Engel auf der Spitze eines Stiftes? Sie müssen den Konstruktor irgendwo schreiben, damit der Compiler sie instanziiert. –

Antwort

3

Da der Konstruktor und der Destruktor nicht definiert sind überall, deklarieren Sie sie nur. Sie instanziieren explizit die Vorlage in der Foo.cpp-Datei, aber die Funktionen sind noch nicht definiert.

Wenn Sie nur gehen Foo<int> verwenden, dann können Sie den Konstruktor und Destruktor in Foo.cpp definieren,

template<typename T> 
Foo<T>::Foo(){...} // or = default 

und

template<typename T> 
Foo<T>::~Foo(){...} 

und aufgrund der Tatsache, dass Sie explizit die Vorlage instanziiert In der Foo.cpp findet der Linker die Definition. Andernfalls müssen Sie die Definition in der Header-Datei angeben.

+0

Bekam es. Ich übersehe es, weil ich mich auf die externen Vorlagen konzentriert habe. Vielen Dank. – OutOfBound

+0

@OutOfBound Siehe auch https://StackOverflow.com/q/8130602/3093378 für weitere Details über die reale Verwendung von 'externen Vorlagen'. – vsoftco

+0

Ich kann nicht sagen, ob die Absicht des Codes in diesem Beispiel ist, Vorlagenfunktionsdefinitionen für 'Foo ' oder für 'Foo ' zu demonstrieren. Für den ersten, fügen Sie '' vor den zwei '::'; für letzteres benötigen Sie 'template <> Foo :: Foo() {...}' und ähnlich für den Destruktor. –