Forum: Compiler & IDEs C++ statische Template-Variablen Spezialisierung


von Peter (Gast)


Lesenswert?

Hallo zusammen,

ich möchte in einer Template-Klasse einen statischen String anlegen, 
welches den Namen des Template-Typs speichert. Der Name soll über 
typeid(T).name() ermittelt werden:
1
template<class T>
2
class C {
3
    static std::string ownTypename;
4
};
5
6
template<class T>
7
std::string C<T>::ownTypename = typeid(T).name();

Soweit so gut. Da der gcc (4.6.3) dabei etwas seltsame Namen prozutiert 
(mit _Z... am Anfang), möchte ich zum leichteren Debuggen für die 
üblichen Datentypen eine Spezialisierung erstellen:
1
template<>
2
std::string C<int>::ownTypename = "int";

Und das funktioniert nicht so wie erwartet.

Wenn ich die Definition von C<int>::ownTypename in den Header packe, 
meckert der Linker, dass es mehrmals definiert wurde, was ja auch 
nachvollziehbar ist. Wenn ich es in eine .cpp Datei packe, passiert 
etwas, was ich nicht verstehe.

Das Projekt ist noch im Aufbau und ich habe neben den verschiedenen 
Klassen eine main.cpp, wo in main() verschiedene Teile gestestet werden. 
Falls ich die Definition von C<int>::ownTypename in die main.cpp packe, 
compiliert das Projekt und gibt auch den richtigen spezialisierten 
Typstring aus. Falls ich die Definition aber in eine andere .cpp Datei 
lege, sagt der Linker es wäre bereits schon definiert (ja, ich habe die 
Definition aus main.cpp wieder gelöscht). Was das ganze noch seltsamer 
macht, ist dass der Fehler angeblich in
1
/usr/include/c++/4.6/x86_64-linux-gnu/bits/gthr-default.h:241: first defined here
passiert. Das kann ich absolut nicht nachvollziehen, da meines Wissens 
nach die einzelnen .cpp Dateien getrennt kompliert und am Ende 
gleichwertig zusammengelinkt werden.

Noch kurioser ist, dass ich das Projekt ohne die main (aber mit 
Definitionen von ownTypename) zu einer Bibliothek linken kann. Sobald 
ich diese benutze, werden die Spezialisierungen ignoriert. Wenn ich nun 
jedoch versuche, die Definitionen in die main.cpp des anderen Projektes, 
welches die Bibliothek vom ersten Projekt linkt, hinzuzufügen, sagt der 
Linker, die Definitionen gäbe es schon ("multiple definition").

Habe ich da etwas falsch gemacht, oder ist das ein Bug vom gcc, oder 
...?

von tictactoe (Gast)


Lesenswert?

So müsste es gehen:

foo.h:
1
#include <string>
2
#include <typeinfo>
3
4
template<class T>
5
struct C {
6
        static std::string classname;
7
};
8
9
template<class T>
10
std::string C<T>::classname = typeid(T).name();
11
12
extern template std::string C<int>::classname;
foo.cpp:
1
#include "foo.h"
2
3
template<>
4
std::string C<int>::classname = "int";
D.h., C<int>::classname wird in foo.h als explizite 
Template-Instantiierung deklariert, aber nicht definiert. Dadurch weiß 
der Compiler, dass die Definition der Instanz anderswo existiert und 
instantiiert diese spezielle Ausgabe des Templates nicht mehr. Die 
explizite Instanz definieren wir dann in foo.cpp.

von Peter (Gast)


Lesenswert?

extern, das wars!! Danke dir vielmals!

Kannst du mir noch sagen, warum man nach extern template keine <> 
schreiben darf?

von tictactoe (Gast)


Lesenswert?

Bin hier nicht sattelfest. Ich hatte mal folgende Theorie:

template ohne <> leitet man eine Instantiierung ein, template<> leitet 
eine Spezialisierung ein.

Instantiierung: Das Stanzwerkzeug (template) wird benutzt, um ein 
konkretes "Ding" zu generieren. In unserem Fall die konkrete Deklaration 
einer konkreten Variablen.

Spezialisierung: Eine alternatives Stanzwerkzeug (template) für einen 
eingeschränkten Verwendungszweck wird festgelegt.

Diese Theorie versagt aber, denn dann müsste in foo.cpp template ohne <> 
verwendet werden. Das hat bei meinen Tests aber nicht funktioniert. Und 
so wie ich's oben vorschlage, wäre in foo.cpp wieder nur ein Template 
(wenn auch ein spezialisiertes), aber nichts, was eine Instantiierung 
erzwingt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.