Geht das eleganter?



  • Also ich hab mir nicht den ganzen Thread durchgelesen, aber ich würde das vielleicht so machen:

    class IFoo
    {
    public:
        virtual void Bar() = 0; // die "eine Funktion" wo der Datentyp einen Unterschied macht
    };
    
    template <class T> class Foo : public IFoo, private boost::noncopyable
    {
    public:
        Foo(istream& is, size_t count)
        {
            // ...
            m_data.resize(count);
            is.read(reinterpret_cast<char*>(&m_data[0]), count * sizeof(T));
            // ...
        }
    
        virtual void Bar()
        {
            // ...
            // was auch immer "v" ist...
            v[index].SplineB.y = m_data[index] * m_scaleY;
        }
    
    private:
        std::vector<T> m_data;
        // ...
    };
    
    class VarFoo : private boost::noncopyable
    {
    public:
        template <class T> VarFoo(boost::type<T>, istream& is, size_t count) :
            m_foo(new Foo<T>(is, count))
        {
        }
    
    private:
        boost::scoped_ptr<IFoo> const m_foo;
    };
    

    Bei bloss 2 Datentypen ist das vermutlich mehr Code als die "if Orgien" Version, je mehr Datentypen es sind desto besser schneidet die Template-Version ab.
    Vor allem spart man sich die ganzen Fallunterscheidungen zu tippen, und vor allem auch zu warten. Wenig ist lästiger als eine 1-Zeilen änderung an 10 Stellen machen zu müssen weil man sinnlos Code dupliziert hat.



  • Und der Sinn von dem Code ist auch zweifelhaft. Du legst eine liste von IDataType* an. Wieso eine Liste, wenn du eh nur 1 Objekt reinlegst. Und wenn ich diese liste dereferenziere, dann bekomm ich ein IDataType*. Was soll ich damit? Ich will einfach v[index] schreiben und dann den richtigen Typen haben.

    Ich meine mal irgendwo was gelesen zu haben, dass das ein Array sein soll?! (OK. std::vector o.ä. wäre angebrachter gewesen.)

    Ansonsten, wenn du nicht zufrieden bist mit dem, was wir hier zeigen, dann belass es doch einfach bei void.. Die Sprachmittel sind ja schliesslich da, um genutzt zu werden. Und wenn du das Gefühl hast, dass void* das einzig richtige ist, dann kannst du das ja auch ruhig benutzen. (Was nicht bedeutet, dass ich das auch machen würde.)

    Ansonsten versuch doch mal ein exaktes Beispiel zu bringen, dass mit void* genau das macht, was du willst. (mit der dazugehörigen Datei zum einlesen usw.). Dann wissen wir nämlich genau, was du willst und können dir auch genau darauf eine Antwort geben. Ansonsten verschwendest du/wir nur unsere Zeit und am Schluss bist du nicht glücklich und wir haben uns einen Haufen Arbeit für nichts gemacht..



  • SucherDerEleganz schrieb:

    Ganz ehrlich, alle Vorschläge sind mit Kanonen auf Spatzen schießen. ...

    Äh - ich sehe hier keine "Kanonen".
    Der Code, der Dir hier vorgelegt wird, ist weder länger noch komplizierter noch langsamer noch .... als Deiner. Er nutzt lediglich mehr von den C++-Sprachmitteln (aber alles keine Zauberei).

    Und Dein Problem ist auch kein "Spatz".

    SucherDerEleganz schrieb:

    ...WIE (in welcher DATENSTRUKTUR - sprich: was nun als Member statt dem void* stehen soll) ist mir noch immer nicht klar....

    Das ist Dein Problem: Du willst kein anderes (eleganteres) Design, sondern lediglich einen "Programmierkniff", den Du bei Dir reinkopieren kannst, ohne grundlegend etwas zu ändern.
    Da allerdings die von Dir (zu Recht) beklagte "Uneleganz" kein kleiner Schönheitsfehler ("Spatz") ist, wirst Du das, was Du willst, nicht bekommen.

    Oder anders gesagt:

    SucherDerEleganz schrieb:

    ...Geht das eleganter?...

    Nein.
    (jedenfalls nicht unter den von Dir gemachten (und von mir größtenteils als unnötig empfundenen) Vorgaben)

    ... irgendwie habe ich den Eindruck, dass Du das eigentlich die ganze Zeit hören wolltest.

    Gruß,

    Simon2.



  • Man könnte zusammenfassend sagen:

    Ja, es geht eleganter. Aber solang du darauf bestehst dass alles so bleibt wie es ist, gehts eben nicht eleganter.



  • SucherDerEleganz schrieb:

    Und so arrogante Aussagen wie sie von ~john könnt ihr euch auch sparen.

    Arrogant ist hier nur eine Person. Es wird keinerlei Code herausgerückt, so daß es schlicht weg nicht möglich ist einen sinnvollen Vorschlag zu machen. Wenn man void* vermeiden will, muß man das Design entsprechend anpassen und dazu muß man das Programm entsprechend tiefgreifend ändern. Der Hinweis auf Double Dispatch ist insofern von Belang, weil dies der einzige sinnvolle Grund ist noch auf switch case mit TypeIDs in C++ auszuweichen. Macht man es trotzdem hat man einen Designfehler produziert. Bei Altlasten mag das durchaus sinnvoll sein es weiter zu behalten, aber das kann nicht der Regelfall für neuen Code sein.



  • pumuckl@logged_off schrieb:

    Man könnte zusammenfassend sagen:

    Ja, es geht eleganter. Aber solang du darauf bestehst dass alles so bleibt wie es ist, gehts eben nicht eleganter.

    Oder noch kürzer: "besser" ε { "anders" }
    😉



  • Was diskutiert ihr denn überhaupt mit so einer Knallerbse? Eure ganzen Tipps sind doch echt Perlen für die Säue. Ich wurde mal sagen, dass der gute™ TO sich inzwischen eindeutig als Troll™ geoutet hat.



  • Simon2 schrieb:

    Es geht hier um einen einfachen Dispatch (reine Erzeugung) anhand von Typinformationen, die erst zur Laufzeit aus einer Datei gelesen werden.

    Im Falle von zwei Typen ist ein "Dispatch" schon overkill, eine Fallunterscheidung tät es da schon. Wenn man sich allerdings die Mühe macht extra Klassen zu erzeugen und dann Switch&Case mit TypID benutzt, dann vergeht mir der Spaß. Denn in so einem Fall kann man das gleich sauber und elegant machen, d.h. mittels Polymorphie, dafür ist sie ja in C++ vorhanden.

    Simon2 schrieb:

    Das Lesen den ganzen Threads wäre vllt. keine schlechte Idee gewesen. :p 😉 😃

    Da der Thread nur wenig konkrete Information vom Urheber desselben beinhaltet, habe ich mich auf das Querlesen beschränkt. Ich weiß, bis jetzt nicht was sein konkretes Problem ist. Abgesehen davon, daß er Fallweise Floats und Doubles aus einer Datei einlesen muß, wird er nicht nämlich nicht sonderlich konkret.



  • ~john schrieb:

    ...Im Falle von zwei Typen ist ein "Dispatch" schon overkill...

    Ich hatte das schon so verstanden, als ob es um eine deutlich größere Anzahl von Typen geht.

    Hmmmm - ich bin ja auch ein grooooßer Freund von Polymorphie und ein ebenso intensiver Gegner von Typ-IDs (und dezugehörigem Frickelcode).
    Aber wie hättest Du es denn (ohne Typkennzeichner und entsprechendes switch) die Erzeugung von Objekten unterschiedlichen Typs aus einem flat file gelöst ?
    Natürlich kann man das auslagern in ein "Creator", an dem sich Factories registrieren ... aber ohne irgendein Typkennzeichen auskommen ? Da fällt mir gar nichts zu ein.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Aber wie hättest Du es denn (ohne Typkennzeichner und entsprechendes switch) die Erzeugung von Objekten unterschiedlichen Typs aus einem flat file gelöst ?

    Mit überladenen Funktionen für die jeweiligen Typen. Einlesen tut man dann in den entsprechenden Typen, und dann ruft man z.B. eine put Funktion auf. Welche put Funktion dann konkret benutzt wird, entscheidet der Typ der Einlesevariable.



  • Tachyon schrieb:

    ...Mit überladenen Funktionen für die jeweiligen Typen. Einlesen tut man dann in den entsprechenden Typen, und dann ruft man z.B. eine put Funktion auf. Welche put Funktion dann konkret benutzt wird, entscheidet der Typ der Einlesevariable.

    Sorry, hast Du da mal ein Beispiel für ?
    (ich will jetzt nicht in die Fußstapfen des TOs treten, aber es interessiert mich wirklich)

    Ich sage jetzt mal so: Nach meinem Verständnis greifen virtuelle Funktionen erst bei bereits erstellten Objekten (klar - ohne vtable geht's halt nicht) ... aber die Entscheidung, welches Objekt nun erzeugt wird, muss doch vorher stattfinden.
    NACH der Erzeugung braucht man natürlich keinen Typkennzeichner mehr - da weiß jedes Objekt selbst, was für ein Typ es ist (bzw. wie es die virtual-Schnittstelle zu bedienen hat) - aber davor ?

    Oder anders ausgedrückt: Was soll in dem File stehen und wer liest das ein ?

    Gruß,

    Simon2.



  • Simon2 schrieb:

    ...

    Ne, ich rede hier nicht von Polymorphie und spätem binden.
    Ich meinte frühes binden, so ähnlich, wie bei std::ostream:

    void CC::put(int a);
    void CC::put(float a);
    void CC::put(double a);
    //...
    
    CC c(/*...*/);
    //Entscheide, was gelesen wird, in diesem Fall float...
    float input;
    c.put(input); //CC::put(float a)
    

    Irgendwie so.



  • Köstlich. Nur weil ich die vorgeschlagenen Lösung als absolut NICHT elegant finde, bin ich natürlich gleic ein Troll. Aber natürlich, das ist nicht Arroganz von euch - es ist wohl einfach Fakt, dass wenn man Lösungen von euch nicht sofort gut findet man automatisch ein blöder Troll ist. Widerlich so eine Haltung. Und wenn ich lesen muss, dass manche auf Seite 7 das Problem immer noch nicht verstanden habe (obwohl ich mehrmals den KOMPLETTEN Problemcode gepostet habe), kann man sich auch seinen Teil denken.

    Und abzustreiten das der vorgeschlagene Code mit Kanonen auf Spatzen schießen ist, ist auch lächerlich. Um also 2 oder 3 ifs (ich wiederhole: ZWEI oder DREI ifs) im Code zu elimineren soll ich Konstrukte wie template <class T> class Foo : public IFoo, private boost::noncopyable, liste von einem Typ anlegen, wobei ich für jeden Datentyp eine eigene Klasse anlegen soll, reinterpret_casts usw usw.)
    Und Double Dispatching Pattern bei diesem Fall vorschlagen, ist auch mehr als sinnfrei.

    Wie ich bereits gesagt habe: Ich bleibe bei void*. Das hat absolut nichts mit Sturheit zu tun - welch idiotischer Vorwurf. Was glaubt ihr wohl warum ich hier im Forum frage ob es anders geht?
    Wie auch immer, wenn ich die ellenlangen Codes mit dem winzige Code des void* Vergleiche ist die Entscheidung sehr leicht.



  • Es ist für Anfänger normal, dass sie "Eleganz" im Code noch nicht erkennen können.

    Du brauchst dir also keine Vorwürfe zu machen. Nimm jetzt ruhig dein void* und später, viele, viele Bücher später, darfst du dann auch bei den großen Jungs mitspielen.

    Bis dahin könntest du vielleicht auf das Rumtrollen verzichten, ja?



  • Selten ein Forum erlebt mit so vielen arroganten Arschlöchern. 🙄



  • SucherDerEleganz schrieb:

    Selten ein Forum erlebt mit so vielen arroganten Arschlöchern. 🙄

    Aber selbst beleidigend werden, und Informationen verweigern.



  • SucherDerEleganz schrieb:

    Selten ein Forum erlebt mit so vielen arroganten Arschlöchern. 🙄

    Lieber ein Arsch mit Niveau, als eine Blase voller Urin...



  • SucherDerEleganz schrieb:

    Selten ein Forum erlebt mit so vielen arroganten Arschlöchern. 🙄

    Große Worte von einem der nach wenigen Posts anfängt die Intelligenz der Leute anzuzweifeln, die versuchen ihm zu helfen.

    Ich hingegen hab selten ein Forum mit so einer Anhäufung von Kompetenz und so wenigen A***l**** erlebt.

    Ansonsten stimme ich Tachyon zu.



  • Tachyon schrieb:

    Simon2 schrieb:

    ...

    Ne, ich rede hier nicht von Polymorphie und spätem binden.
    Ich meinte frühes binden, so ähnlich, wie bei std::ostream:

    void CC::put(int a);
    void CC::put(float a);
    void CC::put(double a);
    //...
    
    CC c(/*...*/);
    //Entscheide, was gelesen wird, in diesem Fall float...
    float input;
    c.put(input); //CC::put(float a)
    

    Irgendwie so.

    Aber das ist doch exakt dasselbe, wie ich mit meinem template-Ansatz gemacht habe (nur dass Du die overloads ausgeschrieben und Dich mit einem Kommentar um den switch gedrückt) hast... :p 😉 😉

    Gruß,

    Simon2.



  • SucherDerEleganz schrieb:

    Selten ein Forum erlebt mit so vielen arroganten Arschlöchern. 🙄

    Tröste Dich: Das Forum hat schon einige Newbies mit Diva-Komplex überlebt....

    Übrigens: Hat Deine Haltung Dich inzwischen zum Ziel gebracht und Du Dein Problem gelöst ?

    Gruß,

    Simon2.


Anmelden zum Antworten