Template probleme



  • danke drakon dies ist mir zwar bewust nur das die klasse keine abhängikeiten von den template argumenten haben soll da hier keine intigrierten typen verwendet werden sonder selber geschriebene klassen und dies wäre keine alternative da bei bei zwei template argumente und für jedes jeweils 3 oder mehr möglichkeiten die anzahl an entsehenden möglichkeiten viel zu groß wäre und ich das durch einfache ifs auch hinbekommen würde
    robbes lösung ist wie oben geschrieben keine wirkliche alternative nach meinem design



  • Also Spezialisierung funktioniert auch mit selbst definierten Typen..

    Aber wenn ich dich richtig verstehe, dann willst du eher etwas, dass zur Laufzeit entscheidet und das geht mit templates nun mal nicht. Da brauchst du Laufzeitpolymorphie (abstrakte Basisklasse und dann die Typen davon ableiten).

    // was abstraktes
    class base_type
    {...};
    
    class type1 : public base_type {...};
    class type2 : public base_type {...};
    
    ...
    
    ReturnTyp* PSocketFactory::getSocket(std::string const &String1)
    {
     base_type b;
    
     if("Typ1"==String1)
       b = new type1;
     else 
       b = new type2;
    
     return new ReturnTyp<base_type>   
    }
    


  • @ 123:
    Bis auf ganz wenige Ausnahmen hast du durchgehend auf Satzzeichen verzichtet. Kombiniert mit deiner Formulierung finde ich es so sehr schwer, zu verstehen, was du eigentlich sagen willst. Bitte achte dich ein wenig darauf.

    Aber ich habe auch das Gefühl, du vermischst Templates und Laufzeitpolymorphie. Wenn du das mit if -Abfragen zur Laufzeit lösen willst, warum machst du das nicht? Über virtuelle Funktionen solltest du je nach Typ andere Aktionen ausführen können. Da brauchst du nicht mal if s. Wenn du wirklich nicht mehr weiterweisst, gibt es auch noch dynamic_cast , wobei es hier wirklich nur wenige gerechtfertigte Anwendungsfälle gibt.



  • @drakon ich versteh deinen code nicht wirklich
    es wird ja immer die selbe klasse erstelt

    @Nexus die klassen könne ja schon zur laufzeit fertig sein, also zur kompalierungszeit kann schon feststehen wie die klasse zusammen gesetzt ist.
    das mit den ifs will ich nicht machen, da dies bei zwei mal 3 möglichkeiten
    schon enorm viele Kombinationen sind, sowie die Wartbakeit darunter leiden muss und das hinzufügen einer weiteren Klasse nicht gerade einfach ist und mit enorm viel aufwand verbunden ist.

    Da mein Problem extravagant ist möchte ich mal mein Problem allgemein erklären. Ich möchte eine Basisklasse haben von der Unterschiedliche Klassen abgeleitet werden. Diese Basisklasse soll mit einer zweiten Klasse die Benutzerschnitstelle darstellen. Die zweite klasse soll genau 3 parameter übernemen der erste soll die Unterklasse auswählen,
    der 2., sowie der 3. Parameter soll die eigenschaften von der ausgewählten klasse speziallisieren.
    deshalb dacht ich an templates da diese speziallisierung durch einfaches austauschen von klassen geschehen soll.



  • 123 schrieb:

    Die zweite klasse soll genau 3 parameter übernemen

    der erste soll die Unterklasse auswählen,
    der 2., sowie der 3. Parameter soll die eigenschaften von der ausgewählten klasse speziallisieren.

    Hast du etwas in dieser Art gedacht?

    template <typename Unterklasse, typename Eigenschaft1, typename Eigenschaft2>
    ZweiteKlasse;
    

    Was meinst du genau mit "Eigenschaften"? Soll in Abhängigkeit dieser Parameter ein grundsätzlich anderes Verhalten erzeugt werden? Da kannst du entweder verschiedene Klassen mit gleicher Schnittstelle als Template-Argumente übergeben. Oder wenn es nur kleine Dinge sind, eignen sich unter Umständen auch Funktionszeiger, allerdings als Funktions- statt Templateparameter.



  • so ähnlich.
    Hab an so was gedacht:

    template <class Eigenschaft1, class Eigenschaft2>
    Unterklasse1:Basis
    {
    ...
    Eigenschaft1 e1;
    Eigenschaft2 e2;
    };
    

    ja durch die Parameter soll ein anders Verhalten erzeugt werden. Hierführ sollen unterschiedliche Klassen exesterien, die dieses über eine vordefinierte Schnitstelle erzeugen sollen.

    Um eine benutzerfreundliche Schnitstelle zu erhalten und die Klassen gut zu Kapseln habe ich an eine Klasse gedacht die mir die entsprechende Klasse zusammenbastelt (ist glaub eine factory Klasse). Wie die Klasse aussehen soll, sollte durch die 3 Parameterfestgelegt werden

    Da kannst du entweder verschiedene Klassen mit gleicher Schnittstelle als Template-Argumente übergeben

    Dies ist ja das was ich erreichen will aber nicht hinbekomme

    Basis* Erzeuger::getClass(string Klassentyp, string Eigenschaft1, string Eigenschaft2)
    {
      //hier soll die Eigenschaftsklassen bestimmt werden und das ist mein Problem
      //sucht die Abgeleitete Klasse und gibt diese zurück
      return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2>;
    
    }
    
    //im code
    Erzeuger erzeuger;
    Basis* test = erzeuger.getClass("Unterklasse1","Eigenschaft1","Eigenschaft2");
    

    vll wirds jetzt klar. Bei Vorschläge für ein anderes Design nur her damit.



  • ich denk das ich das über Polymorphielösen werde
    indem ich entsprechende Klassen im ctor übergeben werde und mir die Laufzeitpolymorphie zunutzen mach, wobei mich das mit den Templates interressieren würde wie das geht.



  • In Modern C++ Design von Andrei Alexandrescu war glaub ich ein ähnliches Problem mit Lösung beschrieb. Leider hab ich das Buch zurzeit nicht mehr. Wenn es jemand hat kann er vll mal nachschaun ober er sowas in der Art findet.
    Würd mich wirklich interressieren.
    Noch ne frage wie stark ist der Performance verlust bei Laufzeitpolymorthie? Kann man das sagen bzw. welche größen spielen hier eine Rolle. Zwar kommt es in dieser Anwendung nicht unbeding auf Performance an aber es interressiert mich halt.



  • 123 schrieb:

    Dies ist ja das was ich erreichen will aber nicht hinbekomme

    So wie ich das sehe, brauchst du den ersten Template-Parameter, um eine neue Klasse zu erstellen und eindeutig zu identifizieren. Das ist aber unnötig, die Klasse ist schon durch die anderen Parameter genau definiert.

    Ich hatte ungefähr sowas im Sinn:

    template <class Eigenschaft1, class Eigenschaft2>
    class Klasse
    {
        Eigenschaft1 a;
        Eigenschaft2 b;
    
        void FunktionX()
        {
            a.TueDas();
            a.TueDies();
            b.TueDas();
        }
    
        void FunktionY()
        {
            b.TueNichts();
            b.BeginneEtwasZuTun();
        }
    };
    

    Wie du siehst, müssen die Klassen, die für die Template-Parameter Eigenschaft1 und Eigenschaft2 eine Schnittstelle erfüllen. Eigenschaft1 erfordert die Methoden TueDas() und TueDies() , der Typ Eigenschaft2 muss die Memberfunktionen TueDas() , TueNichts() und BeginneEtwasZuTun() bereitstellen.

    Demzufolge kannst du alle Typen übergeben, die diese Anforderungen erfüllen und so deine Klassen leicht auswechseln.



  • Nexus danke für deine Bemühungen, aber
    ich glaub wier werden gerade aneinander vorbei.
    Bei mir ist nicht das Problem die Klasse, die ich erstellen will
    und wie ich die Templates einsetzen muss
    das Problem liegt in der Erzeugerklasse, die aus den Parametern die Klasse zusammen basteln soll.
    Dies ist mein Ziel:

    ...
    Erzeuger erzeuger;
    Basis* test = erzeuger.getClass("Unterklasse1","Eigenschaft1","Eigenschaft2"); 
    //die zu erzeugende Klasse soll so aussehen //Unterklasse1<Eigenschaft1,Eigenschaft2>
    Basis* test1 = erzeuger.getClass("Unterklasse2","Eigenschaft1","Eigenschaft2");
    //die zu erzeugende Klasse soll so aussehen //Unterklasse2<Eigenschaft1,Eigenschaft2>
    ...
    

    Der erste Parameter ist genauso Wichtig wie die andern beiden Parameter, da dieser die entsprechende Unterklasse ausgewählt wird.

    Demzufolge kannst du alle Typen übergeben, die diese Anforderungen erfüllen und so deine Klassen leicht auswechseln.

    Ich will die Typen "übergeben lasse", also von der Erzeuger Klasse
    ich will sowas verhindern

    Basis* Erzeuger::getClass(string Klassentyp, string Eigenschaft1, string Eigenschaft2)
    {
    
      if(Klassentyp=="Unterklasse1")
       {
        if(Eigenschaft1=="Eigenschaft1")
        {
         if(Eigenschaft2=="Eigenschaft2")
         {
          return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2>;
         }
         if(Eigenschaft2=="Eigenschaft2X")
         {
          return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2X>;
         }
        }
        if(Eigenschaft1=="Eigenschaft1X")
        {
         if(Eigenschaft2=="Eigenschaft2")
         {
          return new Unterklasse1<Eigenschaftsklasse1X,Eigenschaftsklasse2>;
         }
         if(Eigenschaft2=="Eigenschaft2X")
         {
          return new Unterklasse1<Eigenschaftsklasse1X,Eigenschaftsklasse2X>;
         }
        }
    
    }
    

    Wie man sehen kann ist hier sehr viel Coderedundanz enthalten, macht dies Unwartbar bei allein einer Unterklasse und zu jedem Template eine auswahl von zwie verschieden Argumenten

    Es geht also nicht um die von dier vorgestellte Klasse. Diese stelt für mich so kein Problem da



  • Sorry, aber ich glaube, jetzt habe ich es ein wenig besser verstanden. Du hast ja vorhin Folgendes geschrieben:

    123 schrieb:

    @Nexus die klassen könne ja schon zur laufzeit fertig sein, also zur kompalierungszeit kann schon feststehen wie die klasse zusammen gesetzt ist.

    Wie sieht das nun aus? Sind die Typen zur Kompilierzeit bekannt? Falls ja, kannst du das nicht über Strings machen, sondern musst konstante Ausdrücke wie enum s verwenden. Dann stellt sich allerdings wieder die Frage, wieso überhaupt ein Mapping notwendig ist und nicht gleich der richtige Typ eingesetzt werden kann (indem man getClass() zu einem Funktionstemplate macht).

    Ansonsten muss man eine völlig andere - und wohl eher unflexible - Herangehensweise wählen. Das Problem ist, dass man keine Typen zur Laufzeit speichern kann. Wenn du den Typ also nicht zur Kompilierzeit weisst, musst du eine Fallunterscheidung mit if machen (oder evtl. switch ). Mir fallen im Moment nur gerade Makros ein, die die Codeduplizierung verringern könnten.



  • Hier eine Methode zur Laufzeit, zwar auch mit Templates, die aber nicht vom String direkt abhängen. Am besten, du versuchst, das Ganze von unten her nachzuvollziehen.

    template <typename TX, typename TY, typename TZ>
    Basis* MapType()
    {
    	return new Klasse<TX, TY, TZ>();
    }
    
    template <typename TX, typename TY>
    Basis* MapType(const std::string& StringZ)
    {
    	if (StringZ == "schnelles Z")				
    	{									
    		return MapType<TX, TY, SchnellZ>();	
    	}									
    	else if (StringZ == "langsames Z")		
    	{
    		return MapType<TX, TY, LangsamZ>();
    	}
    }
    
    template <typename TX>
    Basis* MapType(const std::string& StringY, const std::string& StringZ)
    {
    	if (StringY == "rotes Y")	
    	{									
    		return MapType<TX, RotY>(StringZ);
    	}									
    	else if (StringY == "blaues Y")
    	{							
    		return MapType<TX, BlauY>(StringZ);		
    	}							
    	else if (StringY == "gelbes Y")
    	{									
    		return MapType<TX, GelbY>(StringZ);
    	}
    }
    
    Basis* MapType(const std::string& StringX, const std::string& StringY, const std::string& StringZ)
    {	
    	if (StringX == "einfaches X")				
    	{									
    		return MapType<EinfachX>(StringY, StringZ);		
    	}									
    	else if (StringX == "schwieriges X")		
    	{									
    		return MapType<SchwierigX>(StringY, StringZ);	
    	}
    }
    

    Das Problem momentan ist, dass du immer noch relativ viel ändern musst, wenn eine vierte Klasse (neben X, Y und Z) dazukommt. Mit Präprozessormagie könnte man sicher noch einige Dinge flexibler machen. Aber mit meinem oberen Code hast du wenigstens jede Abfrage nur einmal.



  • leider auch nicht ganz das was ich suche.
    denk ich muss das über die Pholymorthie machen
    und es zur laufzeit entscheiden,
    dann muss der ctor halt zwei Zeiger übernehmen, für jede eigenschaft einen,
    das sollte dann funktionieren.



  • 123 schrieb:

    leider auch nicht ganz das was ich suche.
    denk ich muss das über die Pholymorthie machen
    und es zur laufzeit entscheiden,
    dann muss der ctor halt zwei Zeiger übernehmen, für jede eigenschaft einen,
    das sollte dann funktionieren.

    Dann bist du aber in etwa dort, was ich bereits vorgeschlagen habe, nicht?



  • naja so ähnlich.

    Die strings werden in der erzeuger klasse zu der entsprechenden Klasse aufgelöst.
    Die übergeb ich dann dem Konstruktor
    spricht das was ich über templates zur kompiler zeit machen wollte mach ich jetzt mit Polymorthie zur laufzeit
    ich versuchs jetzt mal umzusetzen und wenns tut kann ich ja mal posten

    hab mir deins noch mal angeschaut.
    Erfüllt zwar doch die aufgabe die ich lösen wollte, bloß schaut das, naja
    nicht so übersichtlich aus. Ich muss dann halt mit der Laufzeitpolyorthie leben.
    Dafür sollte der Quellcode lesbarer sein und einen geringeren overhead sollte dies auch erzeugen wobei ich mir hier nicht sicher bin.
    Bei der Template Methode wird dann doch zur Kompailerzeit jede denkbare klasse die sich ergeben könnte erstelt also jede kombination?

    aber noch mals danke
    auf die Lösung wär ich von alleine glaub nicht gekommen (Template)



  • Ich weiss jetzt nicht genau, welche Lösung du meinst, aber ja templates erzeugen mehr Code, allerdings ohne Nachteile zur Laufzeit. Die Laufzeitpolymorphie ist wessentlich flexibler, jedoch hat es Nachteile in der Geschwindigkeit zur Laufzeit. (jedoch sollten diese Aspekte vernachlässigt werden und eher auf das Problem, welches du lösen willst ausgerichtet sein).

    Bei der Template Methode wird dann doch zur Kompailerzeit jede denkbare klasse die sich ergeben könnte erstelt also jede kombination?

    Wenn nötig ja.



  • hab mir jetzt sowas vorgestellt

    Basis
    {
     virtual void doSomething();
     //...
    }
    
    Unterklasse1:Basis
    {
     //...
     Unterklasse1(Eigenschaft1*,Eigenschaft2*);
     void doSomething();
     //...
     Eigenschaft1* e1;
     Eigenschaft2* e2;
    }
    
    Baisi* Erzeuger::getClass(string Klasse,sting eigenschaft1, string eigenschaft2)
    {
     Eigenschaft1* e1=NULL;
     Eigenschaft1* e2=NULL;
     //...
     else if(eigenschaft1=="Eigenschaft1X") e1=new Eigenschaft1X;
     //...
     else if (eigenschaft2=="Eigenschaft2X") e2=new Eigenschaft2X;
     //...
     else if (Klasse=="UnterKlasse1") return Unterklasse1(e1,e2);
     //...
    }
    
    //Eigenschaften1X ist von Eigenschaften1 abgeleitet
    

    Das was ich hier jetzt über die Polymorthie gemacht hab war am anfang mein ziel durch Tamplets zu machen.



  • 123 schrieb:

    leider auch nicht ganz das was ich suche.
    denk ich muss das über die Pholymorthie machen

    Ich habe ja extra gesagt, dass mein Code zur Laufzeit funktioniert. Die Funktionstemplates dienen nur zur Verhinderung der Codeduplizierung.

    Wo liegt also das Problem?



  • nirgends 😉
    ich implementier beide Möglichkeiten mal und untersuch dan mal das Laufzeitverhalten (Geschwindigkeit etc.) und Größe, wobei größe heute weniger das Problem ist.
    Kennst du einen guten Profiler auser CodeAnalyst von AMD der auch gut auf Intel Prozesoren funktioniert. Sollte aber kostenlos sein


Anmelden zum Antworten