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 wird

    if( 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 einmal

    charData<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 😉


Log in to reply