Cast oder Templates



  • puuuuh..., da muss ich erst mal ein bisschen grübeln drüber. Ich fange gerade erst so mit der STL und Templates an (Daher auch meine dummen Fragen). Sachen wie maps und pairs hab ich zwar schon mal gehört, aber das wars dann auch.



  • Hallo Leute,

    Ich denke, ich hab jetzt eine einfache und elegante Lösung gefunden.
    Warum einfach, wenns auch kompliziert geht:-) Damit sind alle Möglichkeiten
    mit max. 4 Variablen und einer veränderlichen Klasse abgedeckt. Die Abfrage
    selbst läuft zur Compile-Zeit.

    //im Header
    
    #define FP4(f,bpp,Par1,Par2,Par3,Par4)\ 
    (bpp==8)?f<BYTE>(Par1,Par2,Par3,Par4):\
    (bpp==24)?f<CTriple>(Par1,Par2,Par3,Par4):\
    (bpp==32)?f<CQuad>(Par1,Par2,Par3,Par4):\
    f<WORD>(Par1,Par2,Par3,Par4)
    
    #define FP3(f,bpp,Par1,Par2,Par3)\
    (bpp==8)?f<BYTE>(Par1,Par2,Par3):\
    (bpp==24)?f<CTriPle>(Par1,Par2,Par3):\
    (bpp==32)?f<CQuad>(Par1,Par2,Par3):\
    f<WORD>(Par1,Par2,Par3)
    
    .... Analog für alle Fälle FP2, FP1 und FP  
    
    // in der .cpp-Datei
    
    template<class T> void T_OrgImg (void* Dst,void* Org,LPBYTE Pat,int size)
    {  for (int i=0;i< size;i++) if (*(Pat+i)) *((T*)Dst+i)= *((T*)Org+i); }
    
    LPIMG CImg::OrgImg (LPIMG Org)
    {
      Dst= DstImg(0,Org->bpp); // Erstellt ein leeres Image wie Org
      FP4(T_OrgImg,Org->bpp,Dst->Data,Org->Data,Data,Area); //Template-Aufruf
      return Dst;
    }
    
    Auch z.B. ein Flip ist dann für alle Varianten schnell implementiert:
    
    void CImg::Flip (int type)
    { 
      if ((type&FLIP_BOTH)==FLIP_BOTH) FP2(Reverse,bpp,Data,Area);
      int y,pitch=GetPitch(),pos1=0,pos2=Size-pitch;
      else if ((type&FLIP_VERT)==FLIP_VERT) 
        for (int i=0;i<Dy;i++) FP2(Reverse,bpp,Data+i*pitch,Dx);
      else if ((type&FLIP_HORZ)==FLIP_HORZ) {
        LPBYTE Tmp = new BYTE[Size];
        memcpy (Tmp,Data,Size);
        for (y=0;y<Dy;y++) {
          memcpy (Data+pos1,Tmp+pos2,pitch);
          pos1+=pitch; pos2-=pitch;
        }
        delete[] Tmp;
      }
    }
    

    Das Template muss nicht im Header stehen, da es nur intern aufgerufen wird. Die Definition der Klassenfunktion ist kurz und bündig und alles ist paletti!



  • Von Eleganz kann nicht die Rede sein.



  • WTF?? schrieb:

    Von Eleganz kann nicht die Rede sein.

    Warum? Es ist kurz, übersichtlich und hat keine Laufzeiteinbußen.
    Ich muß doch nicht alles furchtbar kompliziert angehen, wenn es ein einfacher #define auch tut!



  • übersichtlich

    🙄



  • schreibs mir doch übersichtlicher, wenn du das Problem verstanden hast!



  • denali schrieb:

    schreibs mir doch übersichtlicher, wenn du das Problem verstanden hast!

    das fängt bei defines an, geht bei einrückung weiter, macht einen Umweg über sinnlose void zeiger obwohl ein template parameter zur verfügung steht, und hört bei fehlenden Kommentaren auf. Ohja, und ein paar Zeilenumbrüche mehr würden dem ganzen auch nicht schaden.

    //edit hier mal so als Beispiel wie es aussehen könnte

    //ich schätze mal, Par1 und Par2 sind void zeiger
    template<class T>
    void FP(T function,int bpp,void* dest,void* source,char* Pat,unsigned int size){
    	if(bpp==24){
    		function((CTriple*)dest,(CTriple*)source,Pat,size);
    	}
    	else if(bpp==32){
    		function((CQuad*)dest,(CQuad*)source,Pat,size);
    	}
    	else if(bpp==8){
    		function((char*)dest,(char*)source,Pat,size);
    	}
    	else{
    		function((short*)dest,(short*)source,Pat,size);
    	}
    }
    // in der .cpp-Datei
    
    struct T_OrgImg{
    	template<class T> 
    	void operator() (T* Dst,T* Org,char* Pat,unsigned int size){
    		for (unsigned int i=0;i< size;i++){
    			if (Pat[i]){
    				Dst[i]=Org[i];
    			}
    		}
    	}
    }
    
    LPIMG CImg::OrgImg (LPIMG Org)
    {
      Dst= DstImg(0,Org->bpp); // Erstellt ein leeres Image wie Org
      FP(T_OrgImg(),Org->bpp,Dst->Data,Org->Data,Data,Area); //Template-Aufruf
      return Dst;
    }
    


  • otze schrieb:

    das fängt bei defines an, geht bei einrückung weiter, macht einen Umweg über sinnlose void zeiger obwohl ein template parameter zur verfügung steht, und hört bei fehlenden Kommentaren auf. Ohja, und ein paar Zeilenumbrüche mehr würden dem ganzen auch nicht schaden.

    Hallo Otze,
    Also erst mal danke, daß du dir die Mühe gemacht hast, das Ganze umzugestalten! Ich muss jedoch leider noch ein paar Sachen dazu anmerken.
    Ich denke, wie jemand formattiert, ist Geschmackssache. Ich hasse halt
    nun mal ellenlange Listings mit tausenden von unnötigen Klammern, die es meiner Meinung nach auch nicht übersichtlicher machen. Wenn auf eine Bedingung nur eine Anweisung folgt, ist die Klammer halt in meinen Augen überflüssig. Außerdem verwende ich generell einen 2er-Tabulator.

    Zugegeben, dein Funktionstemplate schaut etwas hübscher aus, als meine Defines. Und auch das mit dem operator() ist mir noch nicht ganz geläufig. (Ich beschäftige mich erst seit ein paar Tagen mit Templates und Operator-Überladungen)
    Aber leider hast du mein grundlegendes Problem scheinbar doch nicht ganz verstanden. Ich habe nicht nur eine Funktion mit dem Problem der unterschiedlichen Bitmaps, sondern derer zig. Nach deiner Methode, muß ich mir für jede davon zwei eigene Templates schreiben, wobei du sogar im Zuweisungs-Template (FP) castest.
    Was mach ich mit einer Funktion wie:

    LPIMG::CopyRect (LPIMG Dst,CRect& rc,int mode)
    

    Die hat drei - und zwar völlig andere - Parameter (bei mir stimmt das mit dem 5. LPBYTE auch nicht!) Du müsstest also für jeden anderen Fall wieder ein neues Zuweisungs-Template schreiben.
    Meine Defines und void-Parameter sind also durchaus nicht sinnlos. Die gelten immer, und die Anpassung und das Casten für die jeweilige Routine ist ein Zweizeiler (nicht wie bei dir 10!). Daher finde ich meine Defines wie z.B FP3 (Funktion mit 3 Parametern) irgendwie halt doch eleganter.



  • Hallo Otze,
    Also erst mal danke, daß du dir die Mühe gemacht hast, das Ganze umzugestalten! Ich muss jedoch leider noch ein paar Sachen dazu anmerken.
    Ich denke, wie jemand formattiert, ist Geschmackssache. Ich hasse halt
    nun mal ellenlange Listings mit tausenden von unnötigen Klammern, die es meiner Meinung nach auch nicht übersichtlicher machen. Wenn auf eine Bedingung nur eine Anweisung folgt, ist die Klammer halt in meinen Augen überflüssig. Außerdem verwende ich generell einen 2er-Tabulator.

    Hallo denali,
    Natürlich sind diese Klammern geschmackssache, und ich hab das ganze so formatiert, wie es für mich am sinnvollsten bzw hübschesten ist. Ich will dir ja nicht meinen Stil aufzwängen, aber du musst immer daran denken, dass hier im forum Leute deinen code lesen den du präsentierst. Und dein Stil mit dem operator ?: ist halt verdammt eng und unübersichtlich. Das problem ist, dass man nicht sofort sieht was wozu gehört, und-was auch sehr wichtig ist-man kann in deinem zweizeiler nicht einmal absetzen und in gedanken überlegen was du da machen willst.

    Zugegeben, dein Funktionstemplate schaut etwas hübscher aus, als meine Defines. Und auch das mit dem operator() ist mir noch nicht ganz geläufig. (Ich beschäftige mich erst seit ein paar Tagen mit Templates und Operator-Überladungen)

    die Klasse ist ein sogenannter Functor und der operator() hilft dabei das objekt so aussehen zu lassen, als wäre es eine Funktion, weil man direkt Objekt() schreiben kann. Generell sollte man funktoren funktionen vorziehen wenn man Funktionen herumreichen will.

    Aber leider hast du mein grundlegendes Problem scheinbar doch nicht ganz verstanden. Ich habe nicht nur eine Funktion mit dem Problem der unterschiedlichen Bitmaps, sondern derer zig. Nach deiner Methode, muß ich mir für jede davon zwei eigene Templates schreiben, wobei du sogar im Zuweisungs-Template (FP) castest.

    Es war anhand der spärlichen kommentare nicht erkennbar, was du da machen wolltest, da deine jetzigen anforderungen den vom thread anfang nicht mehr entsprechen.Daraus erschliesst sich auch, dass ich den cast als zusätzliches feature eingebaut habe, damit du nicht wieder son hack wie void zeiger casten machen musst.

    Aber wo wir grad mal bei hacks sind: irgendwie kam mir das alles von anfang an wie ein großer hack vor. Imho steht dein ganzes Objekt zwischen den Stühlen, da es die arbeit von 4 verschiedenen Objekten machen muss.
    Dies ist sicher kein glückliches Objekt! Glückliche Objekte haben nur eine Aufgabe.
    Ich weis jetzt nicht, was du mit der Klasse alles machen willst, ich schätze aber mal bilder öffnen/bearbeiten/abspeichern.

    Was du nun machen kannst, ist die datenverwaltung des Bildes an ein anderes Objekt abzutreten, welches die Bilder immer sofern möglich auf ein einheitliches Format bringt, damit du bei jedem Bild gleich verfahren kannst. Dadurch fällt dieser lästige Dispatch(FP) komplett weg, da dich das Bildformat nicht mehr zu interessieren braucht.



  • dein Stil mit dem operator ?: ist halt verdammt eng und unübersichtlich. Das problem ist, dass man nicht sofort sieht was wozu gehört, und-was auch sehr wichtig ist-man kann in deinem zweizeiler nicht einmal absetzen und in gedanken überlegen was du da machen willst.

    Ok, da muss ich dir wahrscheinlich Recht geben. (Ich wusste selber noch gar nicht, daß das so geht!)

    Es war anhand der spärlichen kommentare nicht erkennbar, was du da machen wolltest, da deine jetzigen anforderungen den vom thread anfang nicht mehr entsprechen.

    Ich dachte das wäre spätestens seit dem 4. Beitrag allen klar. Deswegen hab ich auch nicht allzuviele Kommentare verstreut. Ich dachte Namen wie Dst (Destination) und Src (Source) wären selbsterklärend.

    Ja, es soll eine Bildverarbeitungs-Klasse werden, die sowohl Live-Grabbing über DirectShow, Live-Kantendetektion und Objekterkennung, sowie diverse Bildmanipulationen ermöglicht. Die einzige Unbekannte dabei ist halt die Ausgangsbitmap, die von S/W - 32Bit vorliegen kann.
    Ich werd mal über deinen Vorschlag der Delegation nachdenken. Vielleicht ist das ein ganz guter Tipp, obwohl ich damit das Problem ja nur auf eine andere Klasse verlagere.



  • Ich dachte Namen wie Dst (Destination) und Src (Source) wären selbsterklärend.

    das interessante ist ja, dass es sich nicht so auf Fp übertragen lässt 😉 also von wegen selbsterklärend^^

    Ich werd mal über deinen Vorschlag der Delegation nachdenken. Vielleicht ist das ein ganz guter Tipp, obwohl ich damit das Problem ja nur auf eine andere Klasse verlagere.

    das wichtige ist, dass du es aus der verarbeitenden Klasse verlagerst, die soll sich nicht damit rumschlagen müssen, welch ein Format hier vorliegt, sondern einfach damit arbeiten 🙂


Anmelden zum Antworten