2015-05-29 4 views
8

Sind mehrere Instanzen derselben Klassenvorlage mit demselben Typ in verschiedenen Kompilierungseinheiten zulässig? Was ist mit Funktionsvorlagen?Verknüpfung expliziter Klassenvorlageninstanziierung

Ein Beispielcode ist wie folgt:

test.hpp

template <typename T> 
class A 
{ 
    public: 
     T out(); 
}; 

template <typename T> 
T A<T>::out() 
{ 
    return T(1); 
} 

test1.cpp

#include "test.hpp" 
template class A<int>; 
int testFn() 
{ 
    return A<int>().out(); 
} 

test2.cpp

#include "test.hpp" 
template class A<int>; 
extern int testFn(); 
int main() 
{ 
    return testFn() == A<int>().out(); 
} 

Wenn ich laufen

g++ -std=c++11 test1.cpp test2.cpp -o test 

kompiliert, ohne sich zu beschweren, doppelte Definitionen.

Ich bezog mich auf alte Entwürfe von Standard [1] [2], und Annahme, dass die Verbindung Teil nicht zu viel ändert (außer für anonyme Namespaces). Die Klassenvorlage hat eine externe Verknüpfung von 3.5p4 und 14p4. Wenn das der Fall ist, würde ich erwarten, dass g ++ doppelte Definitionen von A :: out() beschweren sollte. Fehle ich hier etwas?

Was passiert, wenn test.hpp eine Funktionsvorlage ohne "static" oder "inline" definiert?

Vielen Dank.

[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf [2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

+2

[temp.spec] p5 * "Für eine gegebene Vorlage und einen gegebenen Satz von Template-Argumenten, - sollte eine explizite Instanziierungsdefinition höchstens einmal in einem Programm erscheinen [...] Eine Implementierung ist nicht erforderlich, um eine zu diagnostizieren Verletzung dieser Regel. "* – dyp

+0

Siehe auch [CWG NAD 1045] (http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1045), die einen Grund enthält, warum dies wahrscheinlich nicht diagnostiziert. – dyp

+0

@dyp, In diesem Fall verletzt mein Programm tatsächlich 14.7.0.5, aber der Standard besagt, g ++ ist nicht erforderlich, um dies zu diagnostizieren und tatsächlich g ++ löste die Multiple-Definition. Aber damit es normkonform ist, sollte ich alle Instanzen in nur einer Übersetzungseinheit definieren und explizite Template Instanziierung ("extern") in anderen Übersetzungseinheiten deklarieren. Hab ich recht? – nocte107

Antwort

1

Eine gute Möglichkeit, die Antworten auf diese Fragen in der Umsetzung zu finden, ist die Verwendung von "nm". Oft sind die verstümmelten C++ - Symbole besser lesbar, wenn Sie die Ausgabe von nm an C++ filt übergeben.

Wenn Sie beispielsweise mit "-c" kompiliert haben, um ".o" s für jede Kompilierungseinheit zu erstellen, können Sie nm ausführen. Wenn ich dies tue, sehe ich, dass die Template-Mitglieder schwache Symbole "W" -Code (auf x86 Linux) sind. Das bedeutet, dass mehrere Definitionen in Ordnung und in einer systemspezifischen Weise sind. Wenn ich eine Funktion mache, die nicht templatisiert ist, erscheint sie als "T" in den entsprechenden Objektdateien in beiden Übersetzungseinheiten. Das wird ein mehrfach definiertes Symbol verursachen.

Normalerweise werden C++ - Vorlagen nach Bedarf instanziiert (ohne vollständige Instanziierung), wodurch Sie zusätzlich zum Deklarationsheader einen Header vom Typ _impl verwenden könnten.

Sie dürfen eine Membervorlage nicht wirklich als statisch definieren (das gibt einen Fehler). Sie können es als Inline definieren. In diesem Fall wird kein Symbol für die Elementvorlage mit nm angezeigt, da es inline ist.

+0

In Ihrer Antwort haben Sie "in einer systemspezifischen Weise" erwähnt. Bedeutet das, dass es nicht durch den Standard spezifiziert ist und möglicherweise nicht tragbar ist? Was meine letzte Frage zu Funktionsvorlagen angeht, meine ich eher allgemeine Funktionsvorlagen als Klassenelementfunktionsvorlagen. Vielen Dank. – nocte107