In Anbetracht der Tatsache, dass der folgende Header, der meine Vorlagenklasse enthält, in mindestens zwei .CPP
Dateien enthalten ist, wird dieser Code korrekt kompiliert:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
Beachten Sie jedoch die Inline in der Spezialisierungsmethode. Es ist erforderlich, einen Linkerfehler zu vermeiden (in VS2008 ist LNK2005), da die Methode mehr als einmal definiert wurde. Ich verstehe das, weil AFAIK eine vollständige Template-Spezialisierung mit einer einfachen Methodendefinition identisch ist.
Wie entferne ich das inline
? Der Code sollte nicht bei jeder Verwendung dupliziert werden. Ich habe Google durchsucht, einige Fragen hier in SO gelesen und viele der vorgeschlagenen Lösungen ausprobiert, aber keine erfolgreich erstellt (zumindest nicht in VS 2008).
Vielen Dank!
Antworten:
Wie bei einfachen Funktionen können Sie Deklaration und Implementierung verwenden. Geben Sie Ihre Header-Deklaration ein:
und füge die Implementierung in eine deiner cpp-Dateien ein:
Vergessen Sie nicht, Inline zu entfernen (ich habe vergessen und dachte, diese Lösung wird nicht funktionieren :)). Auf VC ++ 2005 überprüft
quelle
inline
beim Kopieren / Einfügen zu entfernen . So hat es funktioniert!Sie müssen die Spezialisierungsdefinition in die CPP-Datei verschieben. Die Spezialisierung der Elementfunktion der Vorlagenklasse ist auch dann zulässig, wenn die Funktion nicht als Vorlage deklariert ist.
quelle
Es gibt keinen Grund, das Schlüsselwort inline zu entfernen.
Die Bedeutung des Codes wird dadurch ohnehin nicht geändert.
quelle
inline
Schlüsselwort dazu führt, dass die Funktion tatsächlich inline ist (der Standard besagt, dass der Compiler dies als Hinweis nehmen sollte), können diese zusätzlichen Kopien nicht entfernt werden. Es ist jedoch nur ein Hinweis auf Inline (sein primärer Effekt ist zu sagen "Generiere keine Fehler bei Verbindungskollisionen auf eine bestimmte Weise")Wenn Sie die Inline aus irgendeinem Grund entfernen möchten, ist die Lösung von maxim1000 vollkommen gültig.
In Ihrem Kommentar scheinen Sie jedoch zu glauben, dass das Inline-Schlüsselwort bedeutet, dass die Funktion mit all seinen Inhalten immer inline wird, aber AFAIK, das tatsächlich sehr stark von Ihrer Compiler-Optimierung abhängt.
Zitieren aus den C ++ FAQ
Wenn Sie also nicht wissen, dass diese Funktion Ihre ausführbare Datei tatsächlich aufbläht, oder wenn Sie sie aus anderen Gründen aus dem Header der Vorlagendefinition entfernen möchten, können Sie sie tatsächlich dort belassen, wo sie ohne Schaden ist
quelle
Ich möchte hinzufügen, dass es immer noch einen guten Grund gibt, das
inline
Schlüsselwort dort zu belassen, wenn Sie beabsichtigen, auch die Spezialisierung in der Header-Datei zu belassen.Referenz: https://stackoverflow.com/a/4445772/1294184
quelle
Dies ist ein kleines OT, aber ich dachte, ich würde es hier lassen, falls es jemand anderem hilft. Ich habe über die Spezialisierung von Vorlagen gegoogelt, die mich hierher geführt hat, und obwohl die Antwort von @ maxim1000 richtig ist und mir letztendlich geholfen hat, meine Probleme herauszufinden, habe ich nicht gedacht, dass es sehr klar ist.
Meine Situation ist etwas anders (aber ähnlich genug, um diese Antwort zu hinterlassen, denke ich) als die der OPs. Grundsätzlich verwende ich eine Drittanbieter-Bibliothek mit allen Arten von Klassen, die "Statustypen" definieren. Das Herzstück dieser Typen sind einfach
enum
s, aber die Klassen erben alle von einem gemeinsamen (abstrakten) übergeordneten Element und bieten verschiedene Dienstprogrammfunktionen, wie z. B. das Überladen von Operatoren und einestatic toString(enum type)
Funktion. Jeder Statusenum
unterscheidet sich voneinander und ist nicht miteinander verbunden. Zum Beispiel hat einerenum
die FelderNORMAL, DEGRADED, INOPERABLE
, ein anderer hatAVAILBLE, PENDING, MISSING
usw. Meine Software ist verantwortlich für die Verwaltung verschiedener Arten von Status für verschiedene Komponenten. Es entstand, dass ich dietoString
Funktionen für diese nutzen wollteenum
Klassen, aber da sie abstrakt sind, konnte ich sie nicht direkt instanziieren. Ich hätte jede Klasse, die ich verwenden wollte, erweitern können, aber letztendlich habe ich beschlossen, einetemplate
Klasse zu erstellen , in dertypename
es sich um einen konkreten Status handelt, der . Da alle s völlig unabhängig waren, hatten sie jeweils ihre eigenenenum
Ich habe mich darum gekümmert. Wahrscheinlich kann eine Debatte über diese Entscheidung geführt werden, aber ich hatte das Gefühl, dass dies viel weniger Arbeit war, als jede abstrakteenum
Klasse um eine eigene zu erweitern und die abstrakten Funktionen zu implementieren. Und natürlich wollte ich in meinem Code nur.toString(enum type)
die Zeichenfolgendarstellung dieser Funktionen aufrufen und ausdrucken können, die (nach einigen Recherchen) mithilfe der Vorlagenspezialisierung aufgerufen werden mussten. Das hat mich hierher geführt. Unten ist eine MCVE von dem, was ich tun musste, damit dies richtig funktioniert. Und tatsächlich war meine Lösung etwas anders als die von @ maxim1000.enum
enum
toString
Dies ist eine (stark vereinfachte) Header-Datei für die
enum
s. In Wirklichkeit wurde jedeenum
Klasse in einer eigenen Datei definiert. Diese Datei stellt die Header-Dateien dar, die mir als Teil der von mir verwendeten Bibliothek zur Verfügung gestellt werden:Hinzufügen dieser Zeile, um die nächste Datei in einen anderen Codeblock zu unterteilen:
nächste Datei
nächste Datei
und dies gibt aus:
Keine Ahnung, ob dies die ideale Lösung ist, um mein Problem zu lösen, aber es hat bei mir funktioniert. Unabhängig davon, wie viele Aufzählungstypen ich letztendlich verwende, muss ich nur ein paar Zeilen für die
toString
Methode in die CPP-Datei einfügen, und ich kann die bereits definiertetoString
Methode der Bibliothek verwenden, ohne sie selbst zu implementieren und ohne sie zu erweiternenum
Klasse, die ich verwenden möchte.quelle