Kommentare: virtual template Funktionen



  • Hallo Leute!

    Ich würde gerne wissen, was ihr von folgendem Test haltet:
    virtual template Funktionen

    Ist er Blödsinn, sinnlos und doof? Gibt es Verbesserungsvorschläge? Sind die Beispiele doof? -> einfach eure Meinung dazu schreiben 🙂

    danke 👍



  • Hallo,
    ich habe mein Hirn leider bereits ausgeschaltet und kann deshalb im Moment nicht wirklich etwas sinnvolles dazu sagen. Nur eins vielleicht: ich denke es wäre für das Verständnis besser, wenn du ein konkreteres Beispiel nehmen würdest. Dazu vielleicht noch eine Beschreibung davon, was du genau tun willst.
    So ist das imo auf jeden Fall ziemlich abstrakt.



  • hab n konkreteres beispiel genommen 🙂

    ists jetzt besser?



  • hab n konkreteres beispiel genommen

    ists jetzt besser?

    Für mein "pea-sized brain" auf jeden Fall deutlich einfacher zu verstehen.
    Btw: Kann es sein, dass du vergessen hast PresentationHolder von PresentationInterface abzuleiten?

    Ich habe mir allerdings beim Lesen sofort eine Frage gestellt und zwar:
    Warum verwendest du nicht von Anfang an ein PresentationInterface und eine einfache virtuelle Funktion?
    Wo ist der Vorteil deiner Lösung gegenüber einer klassischen Strategy-Lösung?



  • HumeSikkins schrieb:

    Btw: Kann es sein, dass du vergessen hast PresentationHolder von PresentationInterface abzuleiten?

    :o
    Natürlich. Wird im Text ja auch so erklärt...
    Werde ich sofort ausbessern.

    Warum verwendest du nicht von Anfang an ein PresentationInterface und eine einfache virtuelle Funktion?
    Wo ist der Vorteil deiner Lösung gegenüber einer klassischen Strategy-Lösung?

    Weil es darum geht templates und virtuelle Funktionen zu vereinbaren.
    Das Beispiel ist aus einem Projekt von mir - dort hätte ich natürlich alle Presentation-Klasse verändern können. Warum ich sie nicht gleich in eine Hierachie gepackt habe ist auch leicht zu erklären: sie waren ursprünglich einfach nur functors.

    Und an verschiedenen anderen Stellen im Code funktionierten sie auch so 🙂 Von vornherein eine Hierachie aufzubauen, hätte zu einem Problem geführt:

    BasePresentation* p=new XMLPresentation(&cout);
    foo.printVars(*p);
    

    und aufeinmal sliced sich das XMLPresentation Objekt zu einem BasePresentation Objekt zusammen. Und genau dem wollte ich vorbeugen.

    Wie würdest du zB das Abschlussbeispiel auf herkömmliche Art lösen? (Ohne das Interface zu ändern. Weil zB neben op>> auch noch etwas anderes getan werden muss)

    Natürlich kann man um diesen Trick herumdesignen. Schliesslich ist es ja nur Workaround. Aber manchmal kann man es nicht, bzw. wäre zu aufwendig.
    Und der Vorteil meiner Methode ist: man kann ohne Interface Änderung eine virtuelle Funktion einführen.

    Aber ich glaube das sollte ich im Text etwas klarer ausdrücken!



  • PS:
    Die Presentation-Klassen müssen ja auch nicht zwangsläufig zusammengehören. Denn printVars() kann man ja jeden x-belieben functor, der ein pair<string, string> nimmt übergeben... Da wäre vererbung uU vielleicht garnicht mal so passend.

    Im prinzip geht es eigentlich nur darum, wie man statische Polymorphie durch Dynamische ersetzen kann...



  • Hallo,

    eigentlich ist deine Lösung soweit ich das nach dem ersten Mal durchlesen festgestellt hab, ja mehr als das was du zu Begin erreichen wolltest:

    du löst die Presentation ja soweit ich gesehen hab eigentlich weitgehend von deinem Manager ab,so dass man im Prinzip vererbte Manager mit verschiedenen Presentations kombinieren kann..statt das man statisch durch Vererbung für jeden Manager eine Presentation hätte.

    Aber im Prinzip sieht mir das Ganze ziemlich nach einem OO-Design Pattern aus, wobei ich mir jetzt nicht ganz sicher bin welches, könnte Strategy sein (hab immer n bicßhen Probleme die Namen konkreten Designs zuzuordnen 😃 )

    Btw. du hast ein paar Mal Klammern bei operator() vergessen



  • Hallo nochmal,

    hier noch ein paar Gedanken:

    Blödsinn, sinnlos und doof?

    Ich finde den Artikel weder blödsinn noch sinnlos noch doof. Vielmehr gefällt er mir sogar ganz gut. Er beschreibt verständlich eine nette Spielerei, die, obwohl sie eine Spielerei ist, trotzdem zum Verständnis bestimmter Prinzipien und Lösungstrategien beitragen kann.
    Wenn der Leser nachdenkt, erhält er Einblicke in den Unterschied zwischen Laufzeit- und Compilezeit Polymorphie. Auf der anderen Seite ist die Technik mal wieder ein feines Beispiel für die hilfreiche Anwendung von Indirektion. Wenn der direkte Weg versperrt ist oder zu mühselig, schaue nach einem Umweg. Hier ist der Umweg ja letztlich die Auftrennung von template virtual in einen virtuellen Teil mit einem gemeinsamen Interface und einen "Typcontainer", der dazu dient sttatische Typinformationen zu konservieren. Die Idee statische Typinformationen dort zu speichern, wo man sie noch hat, damit man sie dann anderorts wo sich nicht mehr existiert verwenden kann, ist meiner Meinung noch viel wichtiger als die konkrete Umsetzung die hier beschrieben wird.

    Warum Spielerei? Ich bezeichne das ganze deshalb als Spielerei, da ich sowas in "production code" wohl nie einsetzen würde. Der Code ist nicht gerade das, was man als "intuitiv verständlich" bezeichnen könnte. Auch mit der Wartungsfreundlichkeit ist es imo nicht so weit her. Im Ernstfall würde ich dann wohl zu klassischeren/einfacheren Designs neigen, auch wenn dieses vielleicht nicht ganz so flexibel sind.
    Desweiteren lässt diese Technik doch einiges zu wünschen übrig. Schließlich funktioniert sie nur dann, wenn der Templateparameter keinen Einfluss auf den eigentlichen Algorithmus der virtuellen Methode hat. Auch wird es richtig hässlich, wenn die virtuelle Funktion einen Templateparameter als Rückgabewert hat.

    Genau sowas braucht man aber in der einzige Situation, in der ich mir jemals virtuelle Templatefunktionen gewünscht habe:

    class Analayzer
    {
    public:
    virtual ~Analayzer() = 0;
    template <class FwdIter>
    virtual FwdIter analyze(FwdIter first, FwdIter last);
    // ...
    };
    
    class ConcreteAnalyer : public Analyzer
    {
    public:
    ...
    };
    

    Konkrete Anmerkungen zum Artikel:
    1. Der Absatz:

    Wir haben es geschafft: eine virtuelle Template Funktion. Allerdings gibt es einige Situationen in denen man dies nicht verwenden kann: nämlich exakt dann, wenn wir den Typ wirklich brauchen. Das Verhalten des Typs können wir ja simulieren (mittels Holder und Interface), aber den Tatsächlichen Typ zu ermitteln geht leider nicht. Allerdings kann man sehr viele Workarounds finden.

    ist meiner Meinung nach etwas schwammig. Hier könnte man vielleicht noch etwas deutlicher herausarbeiten was geht und was nicht geht.

    2. Die Parameterisierung von VarManager und co mit dem Templateparameter ContainerT ist für das eigentliche Thema irrelevant und macht das Beispiel damit imo unnötig komplizierter.

    3. Vielleicht wäre es möglich die einzelnen Schritte, die man für die Umwandlung der virtuellen Templatefunktion durchführen muss noch genauer rauszuarbeiten.
    So nach dem Motto:
    Gegegen: Problem bla bla
    Idee: Blub Blub
    Implementation:
    Schritt 1: gemeinsames Interface erstellen, dass die durchzuführende Operation deklariert

    Schritt 2: Typcontainer erstellen, der das Interface implementiert und den konkreten Typ speichert

    Schritt 3: ...

    Schritt 4: ...

    Exkurs: Wie hätte ich das VarManager-Beispiel implementiert?
    1. Keine Ahnung.
    2. Ich vermeide es von konkreten Klassen zu erben.
    3. Der Punkt beim VarManger ist meiner Meinung nach die Trennung von Iteration
    von der eigentlichen Präsentation. Ich würde deshalb in dieser Situation wohl eher sowas machen:

    class VarManager
    {
    public:
    	// natürlich nicht virtual!
    	template<class Presentation>
    	void printVars(Presentation pres) const
    	{
    		reset();
    		for (pair<string, string> p; getNext(p);)
    			pres(p);
    	}
    protected:
    	virtual void reset() 
    	{
    		cursor_ = container_.begin();
    	}
    	virtual bool getNext(pair<string, string>& p)
    	{
    		if (cursor_ != container_.end())
    		{
    			p = *cursor_++;
    			return true;
    		}	
    		return false;
    	}
    private:
    	Container container_;
    	Container::iterator cursor_;
    };
    
    class EnvironmentVarManager : public VarManager
    {
    protected:
    	typedef VarManager Base;
    	virtual void reset() 
    	{
    		cursor_ = container_.begin();
    	}
    	virtual bool getNext(pair<string, string>& p)
    	{
    		if (cursor_ != container_.end())
    		{
    			p = *cursor_++;
    			return true;
    		}	
    		return Base::getNext(p);		// Wichtig!
    	}
    private:
    	Container container_;
    	Container::iterator cursor_;
    };
    

Anmelden zum Antworten