Template spezialisieren
-
drakon schrieb:
Was geht denn mit Spezialisierung nicht?
Das Problem ist, dass ich mich mit Templatespezialisierung nicht wirklich auskenne. Bei Wikipedia lese ich: "Im Unterschied zu Klassentemplates sind Funktionstemplates nicht teilweise sondern nur vollständig spezialisierbar". Ich befürchte, damit ist genau das nicht möglich, was ich machen möchte.
drakon schrieb:
Im Fall wenn das lediglich typedefs auf den gleichen Typ sind, dann könntest du ja einen Wrapper für die Typen schreibeb, damit funktioniert dann auch die Unterscheidung.
Das is ja gerade nicht der Fall. Abgesehen von den 8 bit "ints" die chars sind, sind die restlichen Typen wirkliche ints bzw. shorts oder longs. Daher brauche ich für die chars eine eigene Behandlung.
-
siecpp schrieb:
drakon schrieb:
Was geht denn mit Spezialisierung nicht?
Das Problem ist, dass ich mich mit Templatespezialisierung nicht wirklich auskenne. Bei Wikipedia lese ich: "Im Unterschied zu Klassentemplates sind Funktionstemplates nicht teilweise sondern nur vollständig spezialisierbar". Ich befürchte, damit ist genau das nicht möglich, was ich machen möchte.
Das bezieht sich auf Templates mit mehreren Parametern. Das was du machen willst klingt so, als wäre das kein Problem.
Schema:
template <typename T> T string_to_T(std::string input) { // ...allgemein... } template <> char string_to_T<char>(std::string input) { // ...speziell... }
-
SeppJ schrieb:
Das bezieht sich auf Templates mit mehreren Parametern. Das was du machen willst klingt so, als wäre das kein Problem.
Wenn ich das so mache bekomme ich immer einen Liker Error wegen Mehrfachdefinition.
-
siecpp schrieb:
Wenn ich das so mache bekomme ich immer einen Liker Error wegen Mehrfachdefinition.
Wenn du was wie machst? Stell mal vernünftige Fragen!
-
SeppJ schrieb:
Wenn du was wie machst? Stell mal vernünftige Fragen!
Wenn ich meinen Code gemäß deinem Beispiel ändere. Was war denn daran unverständlich?
template < typename T > T convert(const std::string &value,const std::string &base) { // ... } template <> uint8_t convert<uint8_t>(const std::string &value,const std::string &base) { //... }./xmlParser.o: In function `_Z7convertIhET_RKSsS2_': /cygdrive/d/Andreas/Tools/Workspace/testsuitnewsvn/Debug/../convert.h:63: multiple definition of `unsigned char convert<unsigned char>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' ./main.o:/cygdrive/d/Andreas/Tools/Workspace/testsuitnewsvn/Debug/../convert.h:63: first defined here collect2: ld returned 1 exit status
-
siecpp schrieb:
SeppJ schrieb:
Wenn du was wie machst? Stell mal vernünftige Fragen!
Wenn ich meinen Code gemäß deinem Beispiel ändere. Was war denn daran unverständlich?
Das Zitat das du davor gebracht hast, hat mich verwirrt.
Zu deinem Fehler:
Ahh, das hatte ich vergessen zu erwähnen: Ein vollständig spezialisiertes Template ist keine Template mehr (Template=Schablone), sondern eine vollständig definierte Funktion. Da du die Spezialisierung in einer Headerdatei stehen hast, hast du am Ende mehrere Definitionen der gleichen Funktion im Programm und das ist wie immer nicht erlaubt. Mögliche Abhilfen:
- Templatespezialisierung aus dem Header nehmen und in eine der Source-Dateien schreiben.
- Templatespezialisierung eine interne Bindung geben (mit inline)Je nachdem, was für dich besser passt. Im Zweifelsfall würde ich die erste Methode nehmen.
-
Erstmal vielen Dank für die Informationen!
SeppJ schrieb:
Je nachdem, was für dich besser passt. Im Zweifelsfall würde ich die erste Methode nehmen.
Wie macht man das am "saubersten"? Ne gleichnamige cpp Datei erstellen, die Spezialisierung reinkopieren und den Header includen?
-
siecpp schrieb:
Wie macht man das am "saubersten"? Ne gleichnamige cpp Datei erstellen, die Spezialisierung reinkopieren und den Header includen?
Ja, so würde ich das machen.
-
Hmm ich bekomme jetzt sehr seltsame Fehlermeldungen die ohne die Spezialisierungen nicht da waren:
In file included from ../convert.cpp:16: ../convert.h: In function `T convert(const std::string&, const std::string&)': ../convert.h:34: error: no match for 'operator>>' in 'conv >> std::hex' ../convert.h:38: error: no match for 'operator>>' in 'conv >> std::dec' ../convert.h:42: error: no match for 'operator>>' in 'conv >> std::oct' ../convert.h:50: error: invalid use of undefined type `struct std::stringstream' /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/iosfwd:84: error: declaration of `struct std::stringstream' ../convert.cpp: In function `T convert(const std::string&, const std::string&) [with T = uint8_t]': ../convert.cpp:22: error: variable `std::stringstream conv' has initializer but incomplete type
-
Fehlen da vielleicht noch ein paar includes? Zeig mal bitte etwas mehr Quelltext vom jetzigen Stand des Projekts.
-
convert.h
#include <string> #include <iostream> #include <bitset> template < typename T > T convert(const std::string &value,const std::string &base) { T ret; std::stringstream conv(value); if(base == "hex") { conv >> std::hex >> ret; } else if(base == "dec") { conv >> std::dec >> ret; } else if(base == "oct") { conv >> std::oct >> ret; } else { std::string error="parser error: unknown base type"; throw error; } if (conv.fail()) { std::string error="parser error: can't convert input value to expected type"; throw error; } else { return ret; } }convert.cpp
#include "convert.h" template <> uint8_t convert<uint8_t>(const std::string &value,const std::string &base) { unsigned short temp; std::stringstream conv(value); if(base == "hex") { conv >> std::hex >> temp; } else if(base == "dec") { conv >> std::dec >> temp; } else if(base == "oct") { conv >> std::oct >> temp; } else { std::string error="parser error: unknown base type"; throw error; } if (conv.fail()) { std::string error="parser error: can't convert input value to expected type"; throw error; } else { return temp; } }Include guards habe ich weggelassen
-
Du hast
#include <sstream>vergessen.
-
SeppJ schrieb:
Du hast
#include <sstream>vergessen.
Danke, jetzt bekomme ich wieder:
./xmlParser.o: In function `_ZStoRRSt13_Ios_FmtflagsS_': /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ios_base.h:(.text$_Z7convertIhET_RKSsS2_[unsigned char convert<unsigned char>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)]+0x0): multiple definition of `unsigned char convert<unsigned char>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' ./convert.o:/cygdrive/d/Andreas/Tools/Workspace/testsuitnewsvn/Debug/../convert.cpp:20: first defined here
-
Das ist merkwürdig, der gcc macht da zumindest keine Zicken. Ich sehe da zwei mögliche Gründe:
- Der Compiler macht sich jetzt für xmlparser.cpp seine eigene Spezialisierung des Templates mit unsigned char, weil es deine Spezialisierung in convert.cpp nicht kennt. Diese kollidiert dann später mit der anderen Version. Dagegen hilft eine Forwarddeklaration deiner Spezialisierung in der Header-Datei.
- Du hast noch eine alte version der xmlparser.o, die noch die spezialisierte Version des Templates enthält von bevor du es ausgelagert hast. Dagegen hilft Neukompilieren des ganzen Projekts.
-
SeppJ schrieb:
Das ist merkwürdig, der gcc macht da zumindest keine Zicken. Ich sehe da zwei mögliche Gründe:
- Der Compiler macht sich jetzt für xmlparser.cpp seine eigene Spezialisierung des Templates mit unsigned char, weil es deine Spezialisierung in convert.cpp nicht kennt. Diese kollidiert dann später mit der anderen Version. Dagegen hilft eine Forwarddeklaration deiner Spezialisierung in der Header-Datei.
- Du hast noch eine alte version der xmlparser.o, die noch die spezialisierte Version des Templates enthält von bevor du es ausgelagert hast. Dagegen hilft Neukompilieren des ganzen Projekts.Ersteres hat geholfen. Vielen Dank!