Template - Variablentyp erkennen - aber wie?
-
Hallo,
ich bin schon am verzweifeln was mein Problem anbelangt, vielleicht könnt ihr mir weiter helfen.
Ich möchte ein Template konstuieren, dass in Abhängigkeit vom Übergabetyp die Variable auf Null setzt. Das ganze soll nur geschehen, wenn es sich NICHT um eine klasse handelt.
So sollte es aussehen:
template <class _data_>class charData { public: _data_ raw; charData() { if (??wenn raw != klasse??) // wäre toll wenns eien Methode geben würde die das feststellen könnte!? ZeroMemory(&raw,sizeof(raw)); }; };
versucht hab ich folgendes:
template <class _data_>class charData { void Test(int r) {raw = 0;}; void Test(char r) {raw = char(0);}; void Test(char r[]) {ZeroMemory(&raw,sizeof(raw))}; void Test(meineKlasse t) { }; // und so weiter public: _data_ raw; charData() { Test(raw); }; };
funktioniert super, allerdings nur im "Debug-Modus", compiliere ich im "Release Modus" bekomme ich einen "Internen Compiler Fehler" bei der Stelle "Test(raw);".
Ändere ich das ganze um, benutze Referenzen:
template <class _data_>class charData { void Test(int &r) {raw = 0;}; void Test(char &r) {raw = char(0);}; void Test(char r[]) {ZeroMemory(&raw,sizeof(raw))}; void Test(meineKlasse &t) { }; // und so weiter public: _data_ raw; charData() { Test(&raw); }; };
schimpft er mit einem Fehler: Konvertierung des Parameters 1 von 'char (*)[4]' in 'char []' nicht moeglich
Vielleicht habt ihr eine Idee wie man das (anders) realisieren kann?!
Vielen Dank.
-
Warum willst du etwas nur dann auf 0 setzen, wenn es keine Klasse ist?
Der Name CharData lässt auf eine String-Klasse schließen. Dann ist aber der Konstruktor sicher nicht die einzige Stelle, wo du zwischen primitiven und eigenen Typen unterscheiden musst.
Also kann die Klasse CharData doch einfach verlangen, dass _data_ einen Konstruktor hat, der 0 übernimmt und damit irgendwas anfangen kann. Das klappt bei int, char etc sowieso. Eigene Typen müssen dafür eben einen Konstruktor bereitstellen.Falls du von deinem Ansatz nicht abweichen willst:
Probier mal einen anderen Compiler, vielleicht hat der VC++ da wieder mal bugs.
Du könntest auch Spezialisierungen verwenden, sowas in der Art:template <typename T> void Test(T&) { /* mach nix */ }; template <> void Test(int& i) { i = 0; } // dito für char, float, ...
Damit sparst du dir, die Funktion Test für jeden eigenen Typen zu implementieren.
-
das ganze beim zweiten Beispiel ohne template<>. Beim Überladen ist das nicht notwendig
(ps template<int> void foo(int&) kannst du nur so:foo<12> (ein_int);
aufrufen)
-
Danke für die schnellen Antworten!!
Auf das Template "charData" kann ich leider nciht verzichten, da steckt noch viel mehr Funktionalität dahinter als ich hier gepostet hab.
D.h. die Spezialisierungen kann ich so nivht verwenden.
Das mit dem Kunstruktor hab ich nicht ganz verstanden wie ich das auf mein Beispiel anwenden kann?.
Vielleicht könnt ihr mir da weiterhelfen.Danke.
PS.: Ja es ist der VC6++ Compiler, den zu wechseln ist momentan nicht möglich.
-
davie schrieb:
das ganze beim zweiten Beispiel ohne template<>. Beim Überladen ist das nicht notwendig
Stimmt.
Ich dachte eher an Template-Spezialisierung als an Überladung.
-
Wieso erhältst du eine Fehlermeldung mit "char()[4]" ich sehe nirgends ein char()[4]. hast du vielleicht noch mehr code?
warum musst du data mit nullen füllen?
hast du schon cd9000s vorschlag mit dem überladen ausprobiert?
-
Ich arbeite mit dem CBuilder dort glaube ich gesehn zu haben
im "Hilfe Index der IDE" das es sowas wie ein Sclüsselwort
typeof oder typeId und ein entsprechendes Beispiel
wo das glaube so verwendet wirdif( a typeof class Buch)....
In JAVA gibts sowas auf jedenfall!!!
mfg
-
auf jedenfall hat er mit templates in diesem fall die schnellere und elegantere version
-
ich habs jetzt mal so getestet:
template <class _data_>class charData { private: template <typename T> void Test(T&) {/* mach nix */ OutputDebugString("Class\n");}; template <> void Test(BYTE& i) { i = 0; OutputDebugString("BYTE\n");} template <> void Test(int& i) { i = 0; OutputDebugString("INT\n");} template <> void Test(long& i) { i = 0; OutputDebugString("LONG\n");} template <> void Test(double& i) { i = 0; OutputDebugString("DOUBLE\n");} template <> void Test(char i) { i=char(0); OutputDebugString("CHAR\n");} template <> void Test(char* i) { ZeroMemory(i,sizeof(_data_)); OutputDebugString("CHAR\n");} public: _data_ raw; charData() { Test(raw); };
und es funktioniert so, das ich damit weiter arbeiten kann, auch im "release modus"
typeof gibts in Vc++ leider nicht.. hab schon danach gegoogelt
@davie:
ja, es gibt noch code, bei dem char(*)[4] vorkommt, ich hab ganz bewußt nur "diesen" einen Ausschnitt gepostet, oder möchtest du 205KB an code hier im forum haben?
warum ich "nullen" brauch, warum nicht????vielen dank für tipps, hat mir weitergeholfen!!!
mfg
-
du hast
void Test(char* i) { //einmal ohne dieses template<> ZeroMemory(i,sizeof(_data_)); OutputDebugString("CHAR\n"); }
die methode wird nur aufgerufen, wenn _data_ dasselbe wie char* ist. sizeof(char*) ist immer 1. Nicht sehr nützlich, hm?
eventuell hilft hier strlen aus <cstring> um die länge zu ermitteln.Also, warum jetzt ausgerechnet 0? Um das Element mit etwas "Sinnvollem" zu initialisieren, oder hat es einen speziellen Grund?
Außerdem solltest du vermeiden den unterstrich _ am anfang eines namens zu verwenden. du bekommst sonst uU probleme.
ps
i = char(0)
wenn du den char als '0' haben willst, dann mach
i = '0'
wenn du ihn tatsächlich 0 setzen willst, dann reicht
i = 0
-
@davie: ich versteh dich nicht ganz:
ich hab folgendes:
template <class _data_>class charData { private: template <typename T> void Init(T&) {}; template <> void Init(BYTE& i) { i = 0;} template <> void Init(int& i) { i = 0;} template <> void Init(long& i) { i = 0;} template <> void Init(double& i) { i = 0;} template <> void Init(float& i) { i = 0;} template <> void Init(float& i) { i = 0;} template <> void Init(char i) { i=char(0);} template <> void Init(char* i) { long l = sizeof(_data_); // extra für davie ;-) ZeroMemory(i,l); } public: _data_ raw; charData() { Init(raw); }; };
zum Aufruf:
charData<char> c; // geht in Init(char i) charData<char[5]> c5; // geht Init(char* i) wobei l = 5 ist! charData<char[1]> c1; // geht Init(char* i) wobei l = 1 ist!
was stimmt daran jetzt nicht?
und was ist mit char(0) oder '0' ??? was ist daran falsch? beides geht!
-
PS: der Aufruf charData<char*> hat hier keine Verwendung!
-
ok, wenn du es so genau angibst, dann geht es. nur sizeof(char*) ist nicht sizeof(char[4]).
nur wenn du einmalcharData<char*> c("foo");
verwendest, bekommst du die länge nicht durch sizeof(data)
char(0) und '0' gehen beide, richtig.
es gehen auch cout<<"foo" und cout<<"bar".
nur die ergebnisse sind anders.char(0) != '0' char(0) == '\0' //idr
-
davie schrieb:
nur sizeof(char*) ist nicht sizeof(char[4]).
Bei mir schon :p
-
schon klar das "sizeof(char*) " die größe der addresse ergibt,
und char(0) passt schon für meine zwecke