Frage

Ich habe einige Template-Code, dass ich es vorziehen würde, in einer CPP-Datei gespeichert haben, anstelle von Inline in der Kopfzeile. Ich weiß, das so lange durchgeführt werden kann, wie Sie wissen, welche Template-Typen verwendet werden. Zum Beispiel:

.h-Datei

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

CPP-Datei

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

Beachten Sie die letzten beiden Zeilen -. Die foo :: Template-Funktion tun nur mit ints und std :: strings verwendet wird, so dass diese Definitionen bedeuten die App verknüpfen

Meine Frage ist - ist dies ein gemeiner Hack oder wird diese Arbeit mit anderen Compilern / Linkern? Ich bin nur diesen Code mit VS2008 zur Zeit verwenden, aber werde in dem Hafen zu anderen Umgebungen werden will.

War es hilfreich?

Lösung

Das Problem, das Sie beschreiben, kann durch die Definition der Vorlage in der Kopfzeile oder über den Ansatz gelöst werden beschreiben Sie oben.

Ich empfehle das Lesen der folgenden Punkte aus der C ++ FAQ Lite :

Sie gehen in vielen Details über diese (und andere) Vorlage Probleme.

Andere Tipps

Für andere auf dieser Seite fragen, was die korrekte Syntax ist (wie ich) für explizite Template-Spezialisierung (oder zumindest in VS2008), sein folgenden ...

In Ihrer .h-Datei ...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

Und in der CPP-Datei

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

Dieser Code ist wohlgeformt. Sie müssen nur darauf achten, dass die Definition der Vorlage an der Stelle der Instanziierung sichtbar ist. Um den Standard zu zitieren, § 14.7.2.4:

  

Die Definition eines nicht ausgeführten Funktionsvorlage, einem nicht ausgeführten Elementfunktion Vorlage oder einem nicht ausgeführten Elementfunktion oder statische Daten Mitglied einer Klasse-Vorlage wird in jeder Übersetzungseinheit vorhanden sein, in dem sie explizit instanziiert wird.

Dies sollte gut funktionieren überall Vorlagen unterstützt werden. Explizite Template-Instantiierung ist Teil des C ++ Standard.

Ihr Beispiel ist richtig, aber nicht sehr beweglich. Es gibt auch eine etwas sauberere Syntax, die (wie erwähnt von @ Namespace-sid) verwendet werden können.

Nehmen wir an die Templat-Klasse Teil einer Bibliothek, die gemeinsam genutzt werden soll. Sollten andere Versionen der Templat-Klasse kompiliert werden? Ist die Bibliothek Betreuer soll alle möglichen Templat Verwendungen der Klasse antizipieren?

Ein alternativer Ansatz ist eine leichte Variation auf das, was Sie haben: eine dritte Datei hinzufügen, die die Vorlage Implementierung / Instanziierung Datei

.

foo.h Datei

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

foo.cpp Datei

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp Datei

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

Die einzige Einschränkung ist, dass Sie den Compiler sagen foo-impl.cpp statt foo.cpp wie Kompilieren des letzteren zu kompilieren tut nichts.

Natürlich können Sie mehrere Implementierungen in der dritten Datei haben oder haben mehrere Implementierungsdateien für jeden Typ Sie verwenden möchten.

Dies ermöglicht viel mehr Flexibilität bei der Templat-Klasse für andere Zwecke zu teilen.

Durch diese Konfiguration reduziert auch mal kompiliert für wiederverwendet Klassen, weil Sie nicht die gleiche Header-Datei in jeder Übersetzungseinheit neu zu kompilieren.

Dies ist auf keinen Fall ein gemeiner Hack, aber der Tatsache bewusst sein, dass Sie es tun müssen (die explizite Template-Spezialisierung) für jede Klasse / Typ, den Sie mit dem angegebenen Vorlage verwenden möchten. Im Fall von vielen Arten anfordernden Vorlage Instanziierung Es gibt eine Menge von Zeilen in Ihrer CPP-Datei sein. Um dieses Problem zu beheben Sie TemplateClassInst.cpp in jedem Projekt haben, können Sie so verwenden, dass haben Sie eine bessere Kontrolle, welche Arten werden instanziiert. Offensichtlich ist diese Lösung wird nicht perfekt sein (auch bekannt als Königsweg), wie Sie die ODR am Ende vielleicht zu brechen.)

Es gibt in dem neuesten Standard, ein Schlüsselwort (export), der dieses Problem zu lindern helfen würde, aber es ist nicht in jedem Compiler implementiert, die mir bewusst bin, anders als Comeau.

Sehen Sie die FAQ-lite darüber .

Ja, das ist der normale Weg specializiation explizite Instanziierung zu tun. Wie Sie erwähnt, können Sie diese Vorlage mit anderen Typen nicht instanziiert.

Edit:. Basierend auf Kommentar korrigierter

Das ist eine Standardmethode Template-Funktionen zu definieren. Ich denke, es gibt drei Methoden, die ich für die Definition Vorlagen lesen. Oder wahrscheinlich 4. Jeder mit Vor-und Nachteilen.

  1. in Klassendefinition definieren. Ich mache das nicht gefallen, weil ich glaube, Klassendefinitionen streng als Referenz und sollte lesen sein einfach. Allerdings ist es viel weniger heikel Vorlagen in der Klasse zu definieren, als draußen. Und nicht alle Vorlage Erklärungen sind auf der gleichen Ebene der Komplexität. Diese Methode macht auch die Vorlage eine echte Vorlage.

  2. Legen Sie die Vorlage im gleichen Header, aber außerhalb der Klasse. Dies ist meine bevorzugte Art und Weise der meisten der Zeit. Es hält Ihre Klassendefinition ordentlich, die Vorlage eine wahre Vorlage bleibt. Es erfordert jedoch vollständige Vorlage Namensgebung, die schwierig sein kann. Auch der Code ist für alle verfügbar. Aber wenn Sie Ihren Code müssen inline sein, dies ist der einzige Weg. Sie können dies auch erreichen, indem eine .INL Datei am Ende Ihrer Klassendefinitionen zu schaffen.

  3. Fügen Sie die header.h und implementation.CPP in Ihre Main.cpp. Ich denke, das ist, wie ihre getan. Sie erhalten keine pre instantiations vorbereiten müssen, wird es wie eine echte Vorlage verhalten. Das Problem habe ich mit ihm ist, dass es nicht natürlich ist. Wir normalerweise nicht enthalten und erwarten, dass Quelldateien enthalten. Ich denke, da Sie die Quelldatei enthalten sind, können die Template-Funktionen inlined werden.

  4. Diese letzte Methode, die der entsandte Weg war, wird die Vorlagen in einer Quelldatei zu definieren, wie Nummer 3; sondern der Quelldatei, einschließlich pre wir die Vorlagen diejenigen instanziiert werden wir brauchen. Ich habe kein Problem mit dieser Methode, und es kommt aber oft sehr praktisch. Wir haben eine große Code haben, kann es nicht von Vorteil inlined wird, so legte es nur in einer CPP-Datei. Und wenn wir wissen, gemeinsame instantiations und wir können sie vordefinieren. Das spart uns vom Schreiben im Grunde den gleichen 5, 10-mal. Diese Methode hat den Vorteil, unseren Code proprietären zu halten. Aber ich empfehle nicht, setzen kleine, regelmäßig genutzte Funktionen in CPP-Dateien. Da dies die Leistung Ihrer Bibliothek reduzieren.

Beachten Sie, ich bin mir nicht bewusst die Folgen einer aufgeblähten OBJ-Datei.

Es ist nichts falsch mit dem Beispiel, das Sie gegeben haben. Aber ich muß sagen, ich glaube, es ist nicht effizient Funktionsdefinitionen in einer CPP-Datei zu speichern. Ich habe nur die Notwendigkeit verstehen, die Funktion der Erklärung und Definition zu trennen.

Bei der Verwendung zusammen mit expliziter Klasse Instanziierung, die Boost-Concept Check Library (BCCL) können Sie Template-Funktion Code in CPP-Dateien erzeugen kann.

Zeit für ein Update! Erstellen Sie ein Inline (.inl oder wahrscheinlich andere Datei) und kopieren Sie einfach alle Ihre Definitionen in ihm. Achten Sie darauf, die Vorlage über jede Funktion (template <typename T, ...>) hinzuzufügen. Anstatt nun einschließlich der Header-Datei in der Inline-Datei tun Sie das Gegenteil. Fügen Sie die Inline-Datei nach die Deklaration Ihrer Klasse (#include "file.inl").

Ich weiß wirklich nicht, warum niemand diese erwähnt hat. Ich sehe keine unmittelbaren Nachteile.

Lassen Sie uns ein Beispiel nehmen, lassen Sie uns aus irgendeinem Grund sagen, dass Sie eine Template-Klasse haben wollen:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

Wenn Sie diesen Code mit Visual Studio kompilieren - es funktioniert aus der Box. gcc wird Linker-Fehler erzeugen (wenn gleiche Header-Datei aus mehreren CPP-Dateien verwendet wird):

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

Es ist möglich, die Umsetzung zu bewegen Datei .cpp, aber dann müssen Sie Klasse wie folgt erklären -

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

Und dann wird CPP wie folgt aussehen:

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

Ohne zwei letzten Zeilen in Header-Datei - gcc wird funktionieren, aber Visual Studio einen Fehler erzeugen:

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

Template-Klasse Syntax ist in Fall optional, wenn Sie Funktion über .dll Export verfügbar machen möchten, aber dies ist nur für Windows-Plattform - so test_template.h könnte wie folgt aussehen:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

mit CPP-Datei aus vorherigem Beispiel.

Dies ist jedoch mehr Kopfschmerzen Linker gibt, so ist es empfehlenswert vorheriges Beispiel zu verwenden, wenn Sie DLL-Funktion nicht exportiert werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top