2008-09-12 6 views
25

Angenommen, ich habe fileA.h, die eine Klasse classA mit Template-Funktion SomeFunc<T>() deklariert. Diese Funktion ist direkt in der Header-Datei implementiert (wie es bei Template-Funktionen üblich ist). Jetzt füge ich eine spezialisierte Implementierung von SomeFunc() (wie für SomeFunc<int>()) in fileA.C hinzu (dh nicht in der Header-Datei).Sichtbarkeit der Template-Spezialisierung der C++ - Funktion

Wenn ich jetzt SomeFunc<int>() aus einem anderen Code (vielleicht auch aus einer anderen Bibliothek) aufrufen, würde es die generische Version oder die Spezialisierung aufrufen?

Ich habe dieses Problem gerade, wo die Klasse und die Funktion in einer Bibliothek leben, die von zwei Anwendungen verwendet wird. Und eine Anwendung verwendet die Spezialisierung korrekt, während eine andere Anwendung die generische Form verwendet (was später zu Laufzeitproblemen führt). Warum der Unterschied? Könnte das mit Linker-Optionen usw. zusammenhängen? Dies ist unter Linux mit g ++ 4.1.2.

Antwort

0

Wenn die spezielle Template-Funktion auch nicht in der Header-Datei aufgeführt ist, kennt die andere Anwendung die spezialisierte Version nicht. Die Lösung ist das Hinzufügen von SomeFunc<int>() zum Header.

9

Haben Sie einen Prototyp mit Parametern zu Ihrer Header-Datei hinzugefügt?

ich meine, ist es irgendwo in fileA.h

template<> SomeFunc<int>(); 

Falls nicht, dass wahrscheinlich der Grund ist.

0

Brandon: das ist, was ich dachte - die spezialisierte Funktion sollte nie aufgerufen werden. Was für die zweite Anwendung gilt, die ich erwähnte. Die erste App ruft jedoch eindeutig das spezialisierte Formular auf, obwohl die Spezialisierung nicht in der Header-Datei deklariert ist!

ich hauptsächlich Erleuchtung suche hier :-) weil die erste App ein Unit-Test ist, und es ist bedauerlich, einen Fehler zu haben, die im Test aber in der realen App erscheint nicht ...

(PS : ich habe diesen bestimmten Fehler behoben, in der Tat durch die Spezialisierung im Header erklärt, aber was andere ähnliche Fehler immer noch versteckt sein könnte)

2

Pro die Spezifikationen, Ihre spezielle Funktion Vorlage sollte nie außerhalb fileA.C, es sei denn, Sie export genannt werden? die Template-Definition, die kein Compiler (außer Comeau) derzeit unterstützt (oder für die vorhersehbare Zukunft geplant hat).

Auf der anderen Seite, sobald die Funktionsvorlage instanziiert wird, gibt es eine Funktion für den Compiler sichtbar, die nicht mehr eine Vorlage ist. GCC kann diese Definition für verschiedene Compilereinheiten wiederverwenden, da der Standard angibt, dass jede Vorlage nur einmal für eine gegebene Menge von Typargumenten [temp.spec] instanziiert werden soll. Da die Vorlage jedoch nicht exportiert wird, sollte diese auf die Kompilierungseinheit beschränkt sein.

Ich glaube, dass GCC hier einen Fehler in der Freigabe seiner Liste der instanziierten Vorlagen über Kompilierungseinheiten ausgesetzt sein kann. Normalerweise ist dies eine vernünftige Optimierung, aber es sollte Funktion Spezialisierungen berücksichtigen, die es nicht richtig zu tun scheint.

0

In Microsoft C++ habe ich ein Experiment mit Inline-Funktionen durchgeführt. Ich wollte wissen, was passieren würde, wenn ich inkompatible Versionen einer Funktion in verschiedenen Quellen definieren würde. Ich habe unterschiedliche Ergebnisse erhalten, je nachdem, ob ich einen Debug-Build oder einen Release-Build verwendet habe. In Debug verweigert der Compiler die Inline-Erstellung, und der Linker verknüpft die gleiche Version der Funktion, unabhängig davon, was in der Quelle enthalten ist.In Release hat der Compiler inline angegeben, welche Version zu der Zeit definiert wurde, und Sie haben unterschiedliche Versionen der Funktion erhalten.

In beiden Fällen gab es keine Warnungen. Ich habe das irgendwie vermutet, weshalb ich das Experiment gemacht habe.

Ich gehe davon aus, dass Template-Funktionen sich genauso verhalten würden wie andere Compiler.

22

Es ist ein Fehler, um eine Spezialisierung für eine Vorlage zu haben, die am Aufrufpunkt nicht sichtbar ist. Unglücklicherweise müssen Compiler diesen Fehler nicht diagnostizieren und können dann mit ihrem Code tun, was sie wollen (im Standard ist es "schlecht geformt, keine Diagnose erforderlich").

Technisch, müssen Sie die Spezialisierung in der Header-Datei definieren, aber fast jeder Compiler wird damit umgehen, wie man erwarten könnte: dies ist in C++ 11 mit der neuen „extern template“ Anlage behoben:

extern template<> SomeFunc<int>(); 

Dies erklärt ausdrücklich, dass die spezielle Spezialisierung an anderer Stelle definiert ist. Viele Compiler unterstützen dies bereits, einige mit und einige ohne die extern.

0

@ [anthony-williams],

sind Sie sicher, dass Sie extern Vorlage Erklärungen mit extern template instantiations nicht verwirrend? Von dem, was ich sehe, extern template kann nur für explizite Instanziierung verwendet werden, nicht für Spezialisierung (was implizite Instanziierung bedeutet). [Temp.expl.spec] erwähnt nicht die extern Stichwort:

explizite Spezialisierung:
        template <>Erklärung

+0

Damnit, die automatische Verknüpfung des Benutzernamens nicht funktioniert. –

3

hatte ich das gleiche Problem mit gcc4, hier ist, wie ich es gelöst habe. Es war einfacher eine Lösung als das, was ich von früheren Kommentaren glauben konnte. Die Ideen der vorherigen Beiträge waren korrekt, aber ihre Syntax funktionierte nicht für mich.


    ----------header----------------- 
    template < class A > 
    void foobar(A& object) 
    { 
     std::cout << object; 
    } 

    template <> 
    void foobar(int); 

    ---------source------------------ 
    #include "header.hpp" 

    template <> 
    void foobar(int x) 
    { 
     std::cout << "an int"; 
    } 

+0

SOB, die in der Vorschau formatiert wurde! Es tut uns leid –

1

Wie Anthony Williams sagt, ist das extern template Konstrukt der richtige Weg, dies zu tun, aber da sein Beispielcode unvollständig ist und mehrere Syntaxfehler hat, hier ist eine komplette Lösung.

fileA.h:

namespace myNamespace { 
    class classA { 
    public: 
     template <class T> void SomeFunc() { ... } 
    }; 

    // The following line declares the specialization SomeFunc<int>(). 
    template <> void classA::SomeFunc<int>(); 

    // The following line externalizes the instantiation of the previously 
    // declared specialization SomeFunc<int>(). If the preceding line is omitted, 
    // the following line PREVENTS the specialization of SomeFunc<int>(); 
    // SomeFunc<int>() will not be usable unless it is manually instantiated 
    // separately). When the preceding line is included, all the compilers I 
    // tested this on, including gcc, behave exactly the same (throwing a link 
    // error if the specialization of SomeFunc<int>() is not instantiated 
    // separately), regardless of whether or not the following line is included; 
    // however, my understanding is that nothing in the standard requires that 
    // behavior if the following line is NOT included. 
    extern template void classA::SomeFunc<int>(); 
} 

fileA.C:

#include "fileA.h" 

template <> void myNamespace::classA::SomeFunc<int>() { ... }