Methoden mit bool-Parametern und "Lesbarkeit" im Kontext



  • Shade Of Mine schrieb:

    Sag mir einfach ob folgender Code korrekt ist:

    window = Fullscreen;
    window = Border3D;
    

    Niemand kann es sagen. Ist Fullscreen und Border3D vom selben Flag-Typ? Wenn ja: böser Fehler, wenn nein dann funktioniert es.
    Es kompiliert anstandslos. egal was nun der Fall ist. Gefährliches Problem.

    Es kompiliert nicht, warum der Code eindeutig falsch ist, steht im Posting zuvor.

    Shade Of Mine schrieb:

    window = a;
    window = b;
    
    &a == &b //false
    &window == &a //true
    

    das verwirrt jeden leser erstmal gehörig. es ist nämlich ein absolut unnatürliches verhalten.

    Das Zweite ist false.

    Shade Of Mine schrieb:

    - Ausserdem ist es eine kuerzere Schreibweise.

    sobald das als argument genannt wird, sollten alle alarmglocken läuten.

    schreibfaulheit ist nie ein guter grund.

    Schreibfaulheit ist in Algorithmen ein sehr guter Grund, weil je weniger Blah-Text, desto mehr kann man sich auf den Algorithmus konzentrieren. Dafür nehme ich in Kauf, dass die Erstellung der Flags aufwendiger(!) ist.
    Schreibfaulheit selbst ist also nicht das Ziel der Flag-Klassen.

    Shade Of Mine schrieb:

    davon dass window keine flags ist sondern hat - ok, wir wissen ja wie verkorkst hier manche leute OOP sehen 😉

    Und wir wissen, dass manche Leute, andererleuts Postings nicht lesen oder nicht verstehen. 😉

    Dir gefällt die Idee nicht, das ist okay.
    Die Idee scheint mir von Dir noch nicht ganz verstanden zu sein. Es steht Dir frei das ganze mal auszuprobieren und auszutesten und es steht Dir auch frei dagegen zu sein. Deine Argumentation haben aber nichts mit den Flag-Klassen zu tun.



  • Xin schrieb:

    Auch auf die Gewissheit hin, dass ich mich wiederhole: Es geht nicht...

    Warum antworte ich Deine Postings, wenn Du sie nicht liest!?

    Alle meine Beispiele gehen sehr wohl - nicht immer 1:1 auf deinen Beispielcode bezogen, aber da du sowieso keinen kompletten Code gepostest hast ist sowas kaum zu vermeiden.

    DEvent schrieb:

    win = Fullscreen | Modal;
    

    Sowas waere echt cool, wenns denn moeglich waere...

    Auch auf die Gewissheit hin, dass ich mich wiederhole: Es geht nicht...

    Und auch das ist problemlos möglich.

    Nicht immer ist dein Code das einzig mögliche. Wenn man ein win = Fullscreen | Modal will, dann kann man es machen. Technisch absolut kein Problem. Aber es geht hier nicht um Technik.

    Edit: Da Shade immernoch falschen Code verbreitet hier nochmal der richtige:

    win = WindowFlags::FullScreen;     // WindowFlags & WindowFlags::operator = ( WindowFlags const & ) - gibt's => geht
    win = WindowMode::Modal;           // WindowMode  & WindowMode ::operator = ( WindowMode  const & ) - gibt's => geht
    

    Auch wenn es dich schockiert - ob man nun WindowFlags/WindowMode oder sonstwas qualifiziert - es bleibt ein a=b für den Leser.

    Zwei nicht verwandte Typen, die Shade hier mit | verbindet:

    win = WindowFlags::FullScreen | WindowMode::Modal; //  ??? & operator ???::operator | ( WindowFlags & const, WindowMode const & )  - Gibt's nicht => geht nicht
    

    Ich sehe 0 Probleme sowas technisch zu implementieren.

    Und nochmal: Du musst angeben, welchen Typ der Flag hat, darum ist es eindeutig. Ohne Typ, kein Flag. Darum hat der Code von Shade nichts mit meinen Flagklassen zu tun.

    Ob ich qualifiziere oder nicht ändert den Code kein bisschen. Mal abgesehen davon dass ich nicht immer qualifizieren _muss_ - zB in der Window Klasse drinnen.

    Wenn operator & für zwei Fenster nicht deklariert ist, würde eine Hirachie hochgegangen und das Ergebnis wären übereinstimmende WindowFlags, genauso wie wnd1->Flags & wnd2->Flags.
    Wenn Dir das nicht gefällt, deklariere operator & als private member.

    Mehr Code komplexität.

    Shade Of Mine schrieb:

    window = a;
    window = b;
    
    &a == &b //false
    &window == &a //true
    

    das verwirrt jeden leser erstmal gehörig. es ist nämlich ein absolut unnatürliches verhalten.

    Das Zweite ist false.

    Ja, mein Fehler. Die & muss man sich wegdenken, ich habe etwas daran herumgebastelt und da ist der Fehler reingerutscht.

    Da b ein Flag ist und somit keine Zuweisung stattfindet, auch wenn da ein op= war, führt das zu schwer zu verstehenden Code.

    Schreibfaulheit ist in Algorithmen ein sehr guter Grund, weil je weniger Blah-Text, desto mehr kann man sich auf den Algorithmus konzentrieren. Dafür nehme ich in Kauf, dass die Erstellung der Flags aufwendiger(!) ist.
    Schreibfaulheit selbst ist also nicht das Ziel der Flag-Klassen.

    Zeig mal bitte ein Beispiel wo Schreibfaulheit besser ist als sinnvolle Namen und Konventionen. Man verwendet deshalb ja auch "sort" und nicht "s" 😉
    Man hat vector<int>::iterator statt einen vector der sich wie ein iterator verhält 😉

    Und wir wissen, dass manche Leute, andererleuts Postings nicht lesen oder nicht verstehen. 😉

    Und manche Leute wollen nicht verstehen. Ja, das wissen wir.

    Dir gefällt die Idee nicht, das ist okay.
    Die Idee scheint mir von Dir noch nicht ganz verstanden zu sein. Es steht Dir frei das ganze mal auszuprobieren und auszutesten und es steht Dir auch frei dagegen zu sein. Deine Argumentation haben aber nichts mit den Flag-Klassen zu tun.

    Du ignorierst ja - genau wie bei der OOP Diskussion die Punkte die dir nicht gefallen.

    Ich habe die Idee durchaus verstanden - es erinnert mich an den Stack in Java. Erspart Schreibarbeit aber das war es auch schon.

    Auch wenn du es wieder ignorieren wirst:
    nenn mir mal die Vorteile von deiner Methode gegenüber nicht vererben.

    Schreibarbeit ist der einzige Vorteil. Es kann keinen anderen geben als Syntax weil es technisch gleichwertig mit "w->Mode" ist.

    Und genau diese Syntax kritisiere ich - auch wenn du die Kritik ignorierst. Das ist mir egal. Ich will nur nicht dass Leute wie DEvent dann prompt auf sowas "reinfallen" und nur die ersparte Schreibarbeit sehen.

    Es gibt eine Menge pitfalls die man beachten muss damit dein Code korrekt läuft. zB w&d ist etwas dass man sehr sehr leicht übersehen kann.

    Dazu eben die von mir genannten logischen Probleme die ich genannt habe.

    Mir ist durchaus klar wie praktisch diese ersparte Schreibarbeit ist. Aber da ersparte schreibarbeit das unwichtigste von allen Punkten ist, zieht das bei mir nicht so. Ich sehe vielmehr die ganzen Probleme, die ich ohne vererbung nicht hätte.

    PS:

    if(win) {
    }
    

    was genau macht das eigentlich?
    testet es ob das fenster in einem guten zustand ist? oder ist es der test auf flags?

    lässt sich alles natürlich definieren - aber wo bleibt die intuition?



  • Shade Of Mine schrieb:

    was genau macht das eigentlich?
    testet es ob das fenster in einem guten zustand ist? oder ist es der test auf flags?

    lässt sich alles natürlich definieren - aber wo bleibt die intuition?

    Intuition in C++ Operatorueberladung? Es ist genauso eine Gewoehnung wie in dem unterem Beispielcode, da sehe ich keinen Unterschied.

    std::string b = "b";
    std::string c = "c";
    std::string a = b + c;
    std::string a = b - c; // ???
    

    Xin hat eigentlich sehr wohl einen Code gepostet, gleich auf Seite 1, die MyClassFlags Klasse.

    Xin schrieb:

    Auch auf die Gewissheit hin, dass ich mich wiederhole: Es geht nicht...
    DEvent, das wäre auch nicht cool, denn die Intention wäre hier nicht verwandte Datenobjete mit | zu verbinden. Und weil sie nicht verwandt sind, geht das auch nicht, also lass Dir von Shade keinen Unsinn einreden. Was Shade schreibt, hat nichts mit meinen Flag-Klassen zu tun, sondern mit Enums und genau die verwende ich nicht.

    Ich meinte eigentlich das Fullscreen und Modal beide Flags sind. Sowas muesste doch gehen. Das man nicht verschiedene Typen miteinander mischen kann, ist logisch.

    window = WindowFlags::Fullscreen | WindowFlags::Modal.
    

    Xin schrieb:

    Man muss schon wissen, was man tut und dass die Flags nicht in einer Vererbungslinie stehen dürfen, weil sie sonst doppelt auftreten, ist wohl klar. Darum Templates, damit man eben nicht eine Vererbungslinie aufbaut.

    Man kann die FlagKlassen aber nicht final/sealed machen? Sonst geht das untere ja nicht. Das ist aber schlecht: Darf zwar von den Flag-Klassen keine speziellen Extended-Flag-Klassen machen, kann aber diese Flag-Klassen nicht gegen Vererbung schuetzen.

    class Window : public FlagClass { }
    

    Also was geht alles:

    window = Flags::Fullscreen; // weist dem Window den Flag Fullscreen zu
    window = Flags::Modal; // weist dem Window den Flag Modal zu
    window = Flags::Fullscreen | Flags::Modal; // weist dem Window beide Flags zu?
    if ( window & Flags::Fullscreen ) // testet, ob Window den Flag Fullscreen hat
    window = window2; // ??
    if ( window & window2 ) // ??
    if ( window ) // ??
    


  • Shade Of Mine schrieb:

    DEvent schrieb:

    win = Fullscreen | Modal;
    

    Sowas waere echt cool, wenns denn moeglich waere...

    Auch auf die Gewissheit hin, dass ich mich wiederhole: Es geht nicht...

    Und auch das ist problemlos möglich.

    Nicht immer ist dein Code das einzig mögliche. Wenn man ein win = Fullscreen | Modal will, dann kann man es machen. Technisch absolut kein Problem.

    Technisch kein Problem. Aber es ist nicht das, was ich vorgeschlagen habe.
    Mit meinem Vorschlag musst Du an den interessanten Punkten Qualifizieren und bei Deinem Befehl wird mit einer Fehlermeldung die Kompilierung verweigert.
    Dann kannst Du nicht etwas anderes schreiben, dann hingehen und mir sagen, dass das Geänderte gegen mein Vorgehen spricht. Man kann vieles machen, aber was Du kritisierst, habe ich nicht gemacht und mein Vorgehen erlaubt es auch nicht.

    Shade Of Mine schrieb:

    Edit: Da Shade immernoch falschen Code verbreitet hier nochmal der richtige:

    win = WindowFlags::FullScreen;     // WindowFlags & WindowFlags::operator = ( WindowFlags const & ) - gibt's => geht
    win = WindowMode::Modal;           // WindowMode  & WindowMode ::operator = ( WindowMode  const & ) - gibt's => geht
    

    Auch wenn es dich schockiert - ob man nun WindowFlags/WindowMode oder sonstwas qualifiziert - es bleibt ein a=b für den Leser.

    Das schockt mich nicht und was Du sagst ist korrekt. Die Qualifizierung sagt aber klar aus, welcher Part durch die Zuweisung betroffen ist.

    Das ist natürlich eine Konvention. Ob einem das gefällt oder nicht ist eine subjektive Geschichte. Als Lösung funktioniert es.

    Shade Of Mine schrieb:

    Zwei nicht verwandte Typen, die Shade hier mit | verbindet:

    win = WindowFlags::FullScreen | WindowMode::Modal; //  ??? & operator ???::operator | ( WindowFlags & const, WindowMode const & )  - Gibt's nicht => geht nicht
    

    Ich sehe 0 Probleme sowas technisch zu implementieren.

    Ich sehe auch kein Problem es zu implementieren.
    Was aber nichts daran ändert, dass ich es weder tat, noch propagierte.
    Anders ausgedrückt: Was hat das mit meinem Vorgehen zu tun?!

    Shade Of Mine schrieb:

    Und nochmal: Du musst angeben, welchen Typ der Flag hat, darum ist es eindeutig. Ohne Typ, kein Flag. Darum hat der Code von Shade nichts mit meinen Flagklassen zu tun.

    Ob ich qualifiziere oder nicht ändert den Code kein bisschen. Mal abgesehen davon dass ich nicht immer qualifizieren _muss_ - zB in der Window Klasse drinnen.

    Es ändert die Lesbarkeit des Codes.

    Das Ziel der Sache ist die Handhabung mit der Window-Klasse (bzw. der Klasse, die zu flaggen ist) zu optimieren und das wird erreicht. Die Windowklasse selbst muss in C++ diszipliniert entwickelt werden. Es muss immer diszipliniert entwickelt werden. Die Windowklasse wird vom "Profi" entworfen, der die Klasse kennt, schließlich entwickelt er sie ja - die Verwendung mit dem Flags sichert dem Unerfahreneren den sicheren Umgang mit der Klasse. Das ist der Punkt.

    Flags sind so alltäglich, dass sie auch standardisiert verwendet werden sollten. C++ bietet keine sprachgestützte Verwendung von Flags. Darum baue ich die Flagklassen.

    Wenn ich eine geflaggte Klasse entwickelt habe, muss ich nicht mehr groß nachdenken, um damit zu arbeiten, oder mir den Namen der Variablen für die Flags raussuchen, wenn ich etwas verkehrt mache meckert der Compiler. Die Flagklasse erhöht meine Produktivität mehr, als mich das Schreiben der Flagklasse ausbremst.

    Das muss auf andere deswegen nicht zwangsläufig zutreffen, ich halte es jedoch für begründet, dass es anderen ebenso gehen kann.

    Shade Of Mine schrieb:

    Shade Of Mine schrieb:

    window = a;
    window = b;
    
    &a == &b //false
    &window == &a //true
    

    das verwirrt jeden leser erstmal gehörig. es ist nämlich ein absolut unnatürliches verhalten.

    Das Zweite ist false.

    Ja, mein Fehler. Die & muss man sich wegdenken, ich habe etwas daran herumgebastelt und da ist der Fehler reingerutscht.

    Da b ein Flag ist und somit keine Zuweisung stattfindet, auch wenn da ein op= war, führt das zu schwer zu verstehenden Code.

    Das ist die Frage nach den Konventionen. Es gibt kein Argument dagegen, wenn Du den Code als schwerer zu verstehen empfindest. Ich habe mich damit mehr beschäftigt, von daher ist was mir offensichtlich ist, einem anderen Leser vielleicht befremdlich.
    Einem Leser, der das Verhalten in einem Framework immer wieder findet, wird sich schnell an das Verfahren gewöhnen.

    Shade Of Mine schrieb:

    Schreibfaulheit ist in Algorithmen ein sehr guter Grund, weil je weniger Blah-Text, desto mehr kann man sich auf den Algorithmus konzentrieren. Dafür nehme ich in Kauf, dass die Erstellung der Flags aufwendiger(!) ist.
    Schreibfaulheit selbst ist also nicht das Ziel der Flag-Klassen.

    Zeig mal bitte ein Beispiel wo Schreibfaulheit besser ist als sinnvolle Namen und Konventionen. Man verwendet deshalb ja auch "sort" und nicht "s" 😉
    Man hat vector<int>::iterator statt einen vector der sich wie ein iterator verhält 😉

    Hinter das "sort" wie "s" setzt Du direkt das Smiley, und dass ein Vector keine 1:1 Beziehung zu Iteratoren hat, wie es bei Window und WindowFlags der Fall ist, ist wohl offensichtlich. Auch hier setzt Du direkt ein Smiley hinter.
    Also verstehe ich die Frage nicht.

    Schreibfaulheit ist eine subjektive Sache.

    Ich mag kein Pascal, weil ich keine Romane schreiben will. Ich empfinde { und } als Vorteil zu begin und end, weil ich die Klammern optisch besser von den Worten trennen kann. Hier sehe ich Schreibfaulheit als Vorteil.
    Bei Template-Templates sehe ich den Vorteil ein typedef oder eine entsprechende Class abzuleiten, statt mir mit endlosen Datentyp-Namen einen Wolf zu schreiben, was keiner mehr durchblickt.

    Mein Vorgehen bietet sinnvolle Namen und Konventionen. Ich muss mich also nicht gegen eins entscheiden.
    Auf dieser Ebene verstehe ich die Frage auch nicht.

    [quote="Shade Of Mine"]

    [quote="Shade Of Mine"]

    Und wir wissen, dass manche Leute, andererleuts Postings nicht lesen oder nicht verstehen. 😉

    Und manche Leute wollen nicht verstehen. Ja, das wissen wir.

    Dir gefällt die Idee nicht, das ist okay.
    Die Idee scheint mir von Dir noch nicht ganz verstanden zu sein. Es steht Dir frei das ganze mal auszuprobieren und auszutesten und es steht Dir auch frei dagegen zu sein. Deine Argumentation haben aber nichts mit den Flag-Klassen zu tun.

    Du ignorierst ja - genau wie bei der OOP Diskussion die Punkte die dir nicht gefallen.

    Jow, ich ignoriere euch immer.

    Ich mache Dinge, die funktionieren, Du sagst, was ich mache ist Scheiße und ich ignoriere das.
    Stimmt.
    Wenn Du mir Argumente bietest, die mir unbekannt sind und ich dann feststelle, dass ich eine Einschätzung überdenken und ändern muss, dann ignoriere ich diese auf keinen Fall - selbst, wenn sie in einer Beleidigung verpackt wären.

    Die OOP-Diskussion brachte auch mir Neues, was neu war wurde nicht ignoriert, sondern durchaus nachrecherchiert. Es war nichts dabei, was im Widerspruch zu meinen Äußerungen steht oder mir zeigt, dass meine Herangehen ungenau wäre.

    Shade Of Mine schrieb:

    Auch wenn du es wieder ignorieren wirst:
    nenn mir mal die Vorteile von deiner Methode gegenüber nicht vererben.

    Habe ich oben, es vereinfacht den Umgang mit der entsprechenden zu flaggenden Klasse und es erhöht die Produktivität.

    Shade Of Mine schrieb:

    Schreibarbeit ist der einzige Vorteil. Es kann keinen anderen geben als Syntax weil es technisch gleichwertig mit "w->Mode" ist.

    Es ist technisch gleichwertig zu w->Mode. Aber C ist auch technisch auch nicht mächtiger als C++, dennoch sehe ich in C++ einige Vorteile.
    C++ ist eigentlich ein Meilenstein für Schreibfaule.

    Shade Of Mine schrieb:

    Es gibt eine Menge pitfalls die man beachten muss damit dein Code korrekt läuft. zB w&d ist etwas dass man sehr sehr leicht übersehen kann.

    Natürlich kann man sich w&d auch aufhängen. Flags von Objekten gegeneinander zu setzen, hat einfach keinen nennenswerten Sinn. Wer einem Programm merkwürdige Fragen stellt, muss mit merkwürdigen Antworten rechnen. Und selbst das passiert hier nicht.
    w&d sind entweder Flags oder mehrdeutig und müssen daher für dem Compiler und damit im Code für den Leser erkennbar erklärt werden.

    Shade Of Mine schrieb:

    Dazu eben die von mir genannten logischen Probleme die ich genannt habe.

    Ich ignoriere Deinen Text nicht, aber sehe Deine Probleme damit nicht, bzw. bewerte sie anders.

    Shade Of Mine schrieb:

    PS:

    if(win) {
    }
    

    was genau macht das eigentlich?
    testet es ob das fenster in einem guten zustand ist? oder ist es der test auf flags?
    lässt sich alles natürlich definieren - aber wo bleibt die intuition?

    Keine Ahnung.

    Was testen if(win) denn, wenn es nicht von etwas anderem abgeleitet ist?
    Ist bool operator() grundsätzlich beschrieben und wenn ja wie?
    Und ist das intuitiver?



  • DEvent schrieb:

    Also was geht alles:

    window = Flags::Fullscreen; // weist dem Window den Flag Fullscreen zu
    window = Flags::Modal; // weist dem Window den Flag Modal zu
    window = Flags::Fullscreen | Flags::Modal; // weist dem Window beide Flags zu?
    if ( window & Flags::Fullscreen ) // testet, ob Window den Flag Fullscreen hat
    window = window2; // ??
    if ( window & window2 ) // ??
    if ( window ) // ??
    

    wieso die fragezeichen?

    window = window2; // window kriegt alle flags von window2
    if ( window & window2 ) // ergibt 'true' wenn mindens 2 flags identisch sind
    if ( window ) // sind irgendwelche flags gesetzt?
    

    so sehe ich das (intuitiv), wenn flags setzen mit = gemacht wird wie oben.
    will man missverständnisse vermeiden, dann besser so: window.flags = Flags::blahblah;



  • Xin schrieb:

    ulfbulf schrieb:

    eine Window klasse von einer WIndowFlags klasse abzuleiten macht keinen sinn 👎
    ach ne moment sind ja eh alles kiddies hier also schnauze cstoll shade etc. 🤡 😋

    Solange Du nicht Mann genug bist, mit einer erkennbaren Identität gegen mich zu trollen, so troll dich. Kritik gegenüber bin ich offen, derartige Pöpeleien machen aus dem Forum einen Kindergarten. Also werd erwachsen.

    versteh ich nicht, ich hab lediglich gesagt dass ich deine meinung nicht teile. sobald jemand deine meinung nicht teilt ist das getrolle? 😕
    angegriffen hab ich auch nur cstoll und shade, also warum beziehst du das posting auf dich? die welt dreht sich nämlich nicht immer nur um dich...
    als trollerei empfind ich eher die quote wars die du hier versuchst mit shade wieder abzuziehen 🙄

    Solltest Du derjenige IRC-Admin sein, der mich im #cpp mit der Begründung gebannt hat, weil er mich im Forum nicht mag und mich nicht aus dem Forum werfen kann, dann kann ich Dir nur sagen: Die Pubertät sollte mit 20 langsam abgeschlossen sein.

    haha, nein tut mir leid, ich bin weder angemeldet in diesem forum, noch jemals in #cpp gewesen, aber trotzdem gut gemacht 🤡 👍



  • DEvent schrieb:

    Also was geht alles:

    window = Flags::Fullscreen; // weist dem Window den Flag Fullscreen zu
    window = Flags::Modal; // weist dem Window den Flag Modal zu
    window = Flags::Fullscreen | Flags::Modal; // weist dem Window beide Flags zu?
    

    Das passt, weil Modal und Fullscreen beide Flags sind - ist aber nicht das, was weiter oben kritisiert wird.
    Da ist Modal ein DialogFlag und Fullscreen ein WindowFlag. Unterschiedliche Klassen => bei Shade geht es nicht.

    Undertaker schrieb:

    window = window2; // window kriegt alle flags von window2
    

    Yepp, sofern nicht überschrieben bzw. ambivalent.

    Undertaker schrieb:

    if ( window & window2 ) // ergibt 'true' wenn mindens 2 flags identisch sind
    

    Yepp, sofern nicht überschrieben bzw. ambivalent.

    Undertaker schrieb:

    if ( window ) // sind irgendwelche flags gesetzt?
    

    Nur wenn bool operator() beschrieben ist. Ist bei mir nicht, weil die Frage ist in der Regel Unsinn. Schließlich stellt man bis zu 32 Fragen gleichzeitig und nicht alle Antworten müssen eine Bedeutung für die Fragestellung haben. Das wäre ein klassischer Bug, nachdem man Flags (egal ob als enum, class oder einfache #defines) erweitert.
    Für aufwendige Abfragen kann die Flagklasse um entsprechende Funktionen oder Flagpackete erweitert werden.

    if( window & WindowFlags::GameCapabilities )
    oder 
    if( window.HasGameCapabilities() )
    statt
    if( window & WindowFlags::OpenGL && window & WindowFlags::FullScreen && window & WindowFlags::NoBorders )
    

    Undertaker schrieb:

    will man missverständnisse vermeiden, dann besser so: window.flags = Flags::blahblah;

    Wenn ihr eine Erweiterung der Konvention als ein derartiges Risiko einschätzt, solltet ihr davon natürlich absehen.
    Für mich stellt sich die Frage nach der Verwendung, bei Flags kommt selten operator = zur Verwendung, vorrangig operator & und operator |=, bzw. &= und ~.
    Flags beantwortet schließlich nicht eine Frage, sondern mehrere und mit operator = modifiziert man grundsätzlich alles - was in der Regel nicht gewünscht ist.



  • Xin schrieb:

    CStoll schrieb:

    Xin schrieb:

    CStoll schrieb:

    Es gibt kein Chaos, da Window sich genauso verhält, als wäre es mit Window::Flags implementiert worden.

    Du hast mir immer noch nicht verraten, was der Ausdruck 'wnd1&wnd2' für eine Bedeutung haben soll.

    Wenn operator & für zwei Fenster nicht deklariert ist, würde eine Hirachie hochgegangen und das Ergebnis wären übereinstimmende WindowFlags, genauso wie wnd1->Flags & wnd2->Flags.
    Wenn Dir das nicht gefällt, deklariere operator & als private member.

    Ist dir klar, daß du dadurch auch die (normal erlaubten) Aufrufe wie 'w&Window::FullScreen' wieder außer Gefecht setzt?

    Nopes, ist mir nicht klar.
    operator & ( Window &, Window & ) fängt w&d ab, aber nicht w & WindowFlag::FullScreen.

    Kennst du den Unterschied zwischen Überladung und Überdeckung? Wenn du in der Window-Klasse einen operator& (privat) definierst, verdeckt der den op&(WindowFlags&) aus der Flag-Klasse - ergo müsstest du diesen per using nachziehen, um ihn noch nutzen zu können. (bei der Alterantive mit einem globalen op&(WindowFlags&,WindowFlags&) bin ich mir nicht sicher, wer für die Überladung einbezogen wird.

    CStoll schrieb:

    Und dafür benötigt die Window-Klasse dann ein halbes Dutzend Zuweisungsoperatoren (und je tiefer du in die Hierarchie runtersteigst, desto mehr werden es ;)).

    Und? Sind alle eindeutig, werden vererbt und es gibt keine tausenden von Funktionen.

    Sie werden eben nicht vererbt, sondern vom (notfalls automatisch generierten) Zuweisungsoperator überdeckt.

    Man muss schon wissen, was man tut und dass die Flags nicht in einer Vererbungslinie stehen dürfen, weil sie sonst doppelt auftreten, ist wohl klar. Darum Templates, damit man eben nicht eine Vererbungslinie aufbaut.

    Ja, man muß wissen, was man tut - und auch auf die Gefahr hin, mich zu wiederholen: Du wirst nicht der einzige bleiben, der durch dieses Gewirr durchblicken muß.

    Xin schrieb:

    DEvent schrieb:

    Also was geht alles:

    window = Flags::Fullscreen; // weist dem Window den Flag Fullscreen zu
    window = Flags::Modal; // weist dem Window den Flag Modal zu
    window = Flags::Fullscreen | Flags::Modal; // weist dem Window beide Flags zu?
    

    Das passt, weil Modal und Fullscreen beide Flags sind - ist aber nicht das, was weiter oben kritisiert wird.
    Da ist Modal ein DialogFlag und Fullscreen ein WindowFlag. Unterschiedliche Klassen => bei Shade geht es nicht.

    Das Problem ist dabei auch die unterschiedliche Bedeutung der Anweisungsfolgen, je nach beteiligten Werten:

    window=WF::Fullscreen;
    window=WF::SysMenu;
    

    ->Window hat nur SysMenu-Stil

    window=WF::Fulscreen;
    window=DF::Modal;
    

    ->Window hat beide Stile.

    Undertaker schrieb:

    window = window2; // window kriegt alle flags von window2
    

    Yepp, sofern nicht überschrieben bzw. ambivalent.

    Undertaker schrieb:

    if ( window & window2 ) // ergibt 'true' wenn mindens 2 flags identisch sind
    

    Yepp, sofern nicht überschrieben bzw. ambivalent.

    Siehst du - und dafür, daß sie nicht überschrieben werden, mußt du selber sorgen.

    Für mich stellt sich die Frage nach der Verwendung, bei Flags kommt selten operator = zur Verwendung, vorrangig operator & und operator |=, bzw. &= und ~.
    Flags beantwortet schließlich nicht eine Frage, sondern mehrere und mit operator = modifiziert man grundsätzlich alles - was in der Regel nicht gewünscht ist.

    Und nun rudert er selber wieder zurück - auch interessant zu sehen 😃 (Fakt ist - du hast den op= und damit wird er auch verwendet).

    PS: Ich hätte zwei Möglichkeiten anzubieten:

    1. Verwendung von Membern - bei "wnd.flag = ..." ist klar, was es darstellen soll
    2. Vererbung, aber dann ohne Operatoren, sondern mit Methoden wie : "wnd.SetFlag(Fullscreen)", "wnd.ResetFlag(FullScreen)", "wnd.HasFlag(FullScreen)"

    Beides vermeidet die Unstimmigkeiten, die dein Design heraufbeschwört.



  • window = window2;
    

    Gefällt mir am besten 🙂
    Der Leser des Codes hat keine Ahnung was das macht. Ist das nicht herrlich?

    Und dass wir immer noch keine Lösung für

    if(win)
    

    ist auch toll.

    Prüft es ob generell Flags gesetzt sind? Oder prüft es ob das Window in einem "guten" Zustand ist bzw. offen ist?

    Natürlich kann man diese Situationen fest definieren und den Anwender des Codes zwingen es sich zu merken. Das lustige ist aber, wenn man die herkömmliche Methode verwendet:

    window.mode = window.mode;
    

    bzw.

    if(window.mode)
    

    ist es sofort klar was gemeint ist. Es gibt keinen Spielraum für Doppeldeutigkeiten.

    Und wenn ich eins gelernt habe, dann das Doppeldeutigkeiten eine furchtbare Fehlerquelle sind.

    Von den ganzen Fallen die diese tolle Syntax hat mal abgesehen. Man muss höllisch mit den operatoren aufpassen - was für welche Typen definiert ist, dabei muss auch die Sichtbarkeit beachtet werden.

    Statt dem lustigen

    Window window;
    window = WndMode::Fullscreen;
    window = WndFlags::Modal;
    

    könnte ein lustiger Anwender auf die Idee kommen

    Window window;
    window = Window::Fullscreen;
    window = Window::Modal;
    

    zu schreiben.

    Die möglichen Komplikationen bei Vererbung mal aussen vorgelassen.

    Pitfalls über Pitfalls.

    Und das alles nur für weniger Schreibarbeit. Ob es das Wert ist, darf sich jeder selber ausdenken.



  • CStoll schrieb:

    Ja, man muß wissen, was man tut - und auch auf die Gefahr hin, mich zu wiederholen: Du wirst nicht der einzige bleiben, der durch dieses Gewirr durchblicken muß.

    Darum entwirre ich es 🙂

    Ich habe übrigens ein Argument gegen die mehrfache Verwendung, das ihr noch nicht habt.

    CStoll schrieb:

    Das Problem ist dabei auch die unterschiedliche Bedeutung der Anweisungsfolgen, je nach beteiligten Werten:

    window=WF::Fullscreen;
    window=WF::SysMenu;
    

    ->Window hat nur SysMenu-Stil

    Erstaunlich. Das ist überzeugend, das wäre bei

    window->Flags = WF::Fullscreen;
    window->Flags = WF::SysMenu;
    

    natürlich ganz anders.

    Unfähigkeit ist kein Argument gegen eine Technik, sondern ein Argument gegen Programmierung. Wer unfähig ist, wird Fehler unabhängig von der Technik prodizieren.

    CStoll schrieb:

    Und nun rudert er selber wieder zurück - auch interessant zu sehen 😃 (Fakt ist - du hast den op= und damit wird er auch verwendet).

    Steine liegen am Wegrand herum. Trotzdem werden sie selten verwendet, um auf andererleuts Köpfen einzuschlagen. Du hast den Stein und damit wird er auch verwendet?

    CStoll schrieb:

    PS: Ich hätte zwei Möglichkeiten anzubieten:
    Verwendung von Membern - bei "wnd.flag = ..." ist klar, was es darstellen soll

    Die Tatsache, dass ich etwas anderes mache, bedeutet ja nicht, dass ich dies hier ablehne. Ich habe eine Alternative vorgeschlagen und das hier nicht verboten.

    CStoll schrieb:

    Vererbung, aber dann ohne Operatoren, sondern mit Methoden wie : "wnd.SetFlag(Fullscreen)", "wnd.ResetFlag(FullScreen)", "wnd.HasFlag(FullScreen)"
    Beides vermeidet die Unstimmigkeiten, die dein Design heraufbeschwört.

    Und die zweite Möglichkeit ist genau das, was ich mache. Nur heißt operator & bei Dir HasFlag usw.
    Ich möchte ja nicht drauf rumreiten, aber vielleicht fällt Dir grade auf, dass Du gegen Dich selbst argumentiert, denn das Umbennenen von Funktionen ändert eine Technik nicht.

    Shade Of Mine schrieb:

    window = window2;
    

    Gefällt mir am besten 🙂

    Dir sollte man auch keine Steine in die Hand geben.

    Nebenher sollten Flags gesetzt und entfernt werden. Der Gleichoperator ist bestenfalls zur Initialisierung und ansonsten bestenfalls eine Fehlerquelle - unabhängig ob als Klasse oder int.

    Shade Of Mine schrieb:

    Und dass wir immer noch keine Lösung für

    if(win)
    

    ist auch toll.

    Prüft es ob generell Flags gesetzt sind? Oder prüft es ob das Window in einem "guten" Zustand ist bzw. offen ist?

    Zum Einen: Die Frage habe ich Dir schonmal beantwortet, Du wiederholst Dich.
    Zum anderen: Die Frage ist nicht intelligenter geworden, denn (nochmals) erstens: es ist in der Regel unsinnig 32 unabhängig Fragen gleichzeitig zu stellen und nur abhängig davon zu reagieren, ob alle Fragen die Antwort "Nein" liefern.
    Zweitens: Das ist das Standardverhalten von Klassen. Meine Klasse liefert ein Standardverhalten. Was Du kritisierst hat also nichts mit der Flag-Klasse zu tun, sondern ist bei jeder Klasse so. Was Du hier - wiederholt - von Dir gibst, hat also auch nichts mit der Thematik zu tun.

    Du kannst ganz toll argumentatieren...

    Shade Of Mine schrieb:

    Natürlich kann man diese Situationen fest definieren und den Anwender des Codes zwingen es sich zu merken.

    Der Punkt ist nicht, dass es zuviele Antworten gibt - es gibt keine, also musst Du Deine Frage vernünftig formulieren.

    Shade Of Mine schrieb:

    Das lustige ist aber, wenn man die herkömmliche Methode verwendet:

    if(window.mode)
    

    ist es sofort klar was gemeint ist. Es gibt keinen Spielraum für Doppeldeutigkeiten.

    Was ist denn jetzt gemeint? Von 32 unabhängigen Fragen gibt mindestens eine Frage ein "Ja" zurück? Hoffentlich nicht eine, die nichts mit dem Algorithmus zu tun hat und die nachträglich implementiert wurde.
    Was hier klar gemeint ist, ist eine wunderbare Gelegenheit, einen Fehler zu bauen.

    Shade Of Mine schrieb:

    Und wenn ich eins gelernt habe, dann das Doppeldeutigkeiten eine furchtbare Fehlerquelle sind.

    ...und jetzt leg die Steine bitte wieder zurück. Du hast aus if( win ) grade if( win.mode ) gemacht, wo der Compiler Dich nicht auf den Unsinn hinweisen kann. Setze lieber um, was Du gelernt hast.

    Shade Of Mine schrieb:

    Statt dem lustigen

    Window window;
    window = WndMode::Fullscreen;
    window = WndFlags::Modal;
    

    könnte ein lustiger Anwender auf die Idee kommen

    Window window;
    window = Window::Fullscreen;
    window = Window::Modal;
    

    zu schreiben.

    Und? Wenn Du eine Klasse ableitest, guckst Du nicht, wovon Du ableitest, was Du überschreiben solltest und was Du auf keinen Fall überschreiben solltest. Und wenn Du mit Steinen um Dich wirfst, guckst Du auch nicht wohin?
    Dann solltest Du Kieshändler werden. 😉

    So, nun mal ein brauchbares Argument gegen die mehrfache Verwendung von Flag-Klassen. Ich brauchte bisher nicht mehrere davon in einem Objekt. Ich habe eben nochmal damit experimentiert, damit ich mich hier nichts falsches erzähle und folgendes passierte: GCC kompiliert es nicht.

    Die Fehlermeldung lautet: der Operatoraufruf ist mehrdeutig. Er ist aber nicht mehrdeutig, es ist sogar sehr eindeutig. Und der Compiler stimmt mir auch zu, benutzt man globale Operatoren, ist auf einmal alles wieder eindeutig, obwohl der zuvor "mehrdeutige" Code nicht verändert wurde.

    Soweit ich weiß, gibt es zwischen den beiden Möglichkeiten, Operatoren zu definieren, keinen semantischen Unterschied. Entweder liege ich da falsch oder der GCC. Grundsätzlich vertraue ich dem Compiler, aber der GCC hätte mein Vertauen nicht zum ersten Mal enttäuscht.

    Ich werde also noch etwas recherchieren, wer von uns beiden hier recht hat. Egal, wer recht hat, der GCC frisst es zur Zeit nicht, was ein klares Argument dafür ist, bei mehrfacher Verwendung von Flagklassen, diese als Member zu verwenden.



  • Xin schrieb:

    Ich habe übrigens ein Argument gegen die mehrfache Verwendung, das ihr noch nicht habt.

    CStoll schrieb:

    Das Problem ist dabei auch die unterschiedliche Bedeutung der Anweisungsfolgen, je nach beteiligten Werten:

    window=WF::Fullscreen;
    window=WF::SysMenu;
    

    ->Window hat nur SysMenu-Stil

    Erstaunlich. Das ist überzeugend, das wäre bei

    window->Flags = WF::Fullscreen;
    window->Flags = WF::SysMenu;
    

    natürlich ganz anders.

    Unfähigkeit ist kein Argument gegen eine Technik, sondern ein Argument gegen Programmierung. Wer unfähig ist, wird Fehler unabhängig von der Technik prodizieren.

    Aber bei der Variante mit expliziten Flags sieht man, ob man nun das selbe Flag beeinflusst/überschreibt oder nicht:

    vergleich mal:

    dlg = Dialog::Fullscreen;//ist eigentlich WindowFlag::Fullscreen
    dlg = Dialog::Modal;//ist DialogFlag::Modal
    

    vs.

    dlg.wFlag = Fullscreen;
    dlg.dFlag = Modal;
    

    CStoll schrieb:

    Und nun rudert er selber wieder zurück - auch interessant zu sehen 😃 (Fakt ist - du hast den op= und damit wird er auch verwendet).

    Steine liegen am Wegrand herum. Trotzdem werden sie selten verwendet, um auf andererleuts Köpfen einzuschlagen. Du hast den Stein und damit wird er auch verwendet?

    Kennst du Murphy's Gesetz? Wenn du einen Operator anbietest, wird auch irgendjemand auf die glorreiche Idee kommen, ihn zu verwenden. Und selbst wenn du so diszipliniert bist, nach der Initialisierung des Fensters nur noch über op|= und op& die Flags zu verwenden, wirst du das kaum von jedem deiner Kollegen voraussetzen können.

    CStoll schrieb:

    PS: Ich hätte zwei Möglichkeiten anzubieten:
    Verwendung von Membern - bei "wnd.flag = ..." ist klar, was es darstellen soll

    Die Tatsache, dass ich etwas anderes mache, bedeutet ja nicht, dass ich dies hier ablehne. Ich habe eine Alternative vorgeschlagen und das hier nicht verboten.

    CStoll schrieb:

    Vererbung, aber dann ohne Operatoren, sondern mit Methoden wie : "wnd.SetFlag(Fullscreen)", "wnd.ResetFlag(FullScreen)", "wnd.HasFlag(FullScreen)"
    Beides vermeidet die Unstimmigkeiten, die dein Design heraufbeschwört.

    Und die zweite Möglichkeit ist genau das, was ich mache. Nur heißt operator & bei Dir HasFlag usw.
    Ich möchte ja nicht drauf rumreiten, aber vielleicht fällt Dir grade auf, dass Du gegen Dich selbst argumentiert, denn das Umbennenen von Funktionen ändert eine Technik nicht.

    Der Unterschied liegt in der Semantik - op& hat eine vordefinierte Bedeutung, die jeder Anwender "versteht" (und bei der man erst einmal überlegen muß, was sie mit dem Problem zu tun hat), HasFlag() drückt durch seinen Namen klar aus, was es für eine Aufgabe hat.
    (und auch auf die Gefahr, mich zu wiederholen, ein Fenster "ist" kein Flag, sondern bestenfalls ein Flagbares Objekt)

    Shade Of Mine schrieb:

    window = window2;
    

    Gefällt mir am besten 🙂

    Dir sollte man auch keine Steine in die Hand geben.

    Wenn du Angst um deine Gesundheit hast, dann solltest du alle erreichbaren Steine schnell wegschließen. Oder würdest du eine geladene Pistole auf dem Tisch liegen lassen, nur mit einem Zettel "bitte nicht anfassen" geschützt?

    Shade Of Mine schrieb:

    Und dass wir immer noch keine Lösung für

    if(win)
    

    ist auch toll.

    Prüft es ob generell Flags gesetzt sind? Oder prüft es ob das Window in einem "guten" Zustand ist bzw. offen ist?

    Zum Einen: Die Frage habe ich Dir schonmal beantwortet, Du wiederholst Dich.
    Zum anderen: Die Frage ist nicht intelligenter geworden, denn (nochmals) erstens: es ist in der Regel unsinnig 32 unabhängig Fragen gleichzeitig zu stellen und nur abhängig davon zu reagieren, ob alle Fragen die Antwort "Nein" liefern.

    Es ist möglich - und irgendwer wird so clever sein, es auch zu machen (und wenn die Window-Klasse nicht explizit dagegensteuert, wird kein Compiler der Welt so einen Müll verhindern)

    Shade Of Mine schrieb:

    Natürlich kann man diese Situationen fest definieren und den Anwender des Codes zwingen es sich zu merken.

    Der Punkt ist nicht, dass es zuviele Antworten gibt - es gibt keine, also musst Du Deine Frage vernünftig formulieren.

    Nein, der Punkt ist, daß du die Semantik des Programms hinter (für Außenstehende) unplausiblen Operatoren und impliziten Typumwandlungen versteckst, statt dem Kind einen Namen zu geben.

    Und? Wenn Du eine Klasse ableitest, guckst Du nicht, wovon Du ableitest, was Du überschreiben solltest und was Du auf keinen Fall überschreiben solltest. Und wenn Du mit Steinen um Dich wirfst, guckst Du auch nicht wohin?
    Dann solltest Du Kieshändler werden. 😉

    Da sind wir wieder bei der Disziplin der Programmierer - du machst es dir einfach, deine Flag-Klasse zu erstellen. Aber jeder, der irgendwas an deinem Framework machen will, muß die Existenz der Klasse bedenken und ein halbes Dutzend Hilfsmethoden implementieren, die nichts machen außer die Anwendbarkeit dieser Flag-Klasse(n) sicherzustellen.

    So, nun mal ein brauchbares Argument gegen die mehrfache Verwendung von Flag-Klassen. Ich brauchte bisher nicht mehrere davon in einem Objekt. Ich habe eben nochmal damit experimentiert, damit ich mich hier nichts falsches erzähle und folgendes passierte: GCC kompiliert es nicht.

    Die Fehlermeldung lautet: der Operatoraufruf ist mehrdeutig. Er ist aber nicht mehrdeutig, es ist sogar sehr eindeutig. Und der Compiler stimmt mir auch zu, benutzt man globale Operatoren, ist auf einmal alles wieder eindeutig, obwohl der zuvor "mehrdeutige" Code nicht verändert wurde.

    Wenn schon der Compiler dir erklärt, daß du Unsinn baust, solltest du es langsam einsehen 😉

    Soweit ich weiß, gibt es zwischen den beiden Möglichkeiten, Operatoren zu definieren, keinen semantischen Unterschied. Entweder liege ich da falsch oder der GCC. Grundsätzlich vertraue ich dem Compiler, aber der GCC hätte mein Vertauen nicht zum ersten Mal enttäuscht.

    Es gibt einen Unterschied zwischen beidem - die Art der Überladungs-Auflösung (das kommen bei Methoden die unterschiedlichen Scopes der beteiligten Klassen dazu, die der Compiler auch mit berücksichtigen muß).

    Ich werde also noch etwas recherchieren, wer von uns beiden hier recht hat. Egal, wer recht hat, der GCC frisst es zur Zeit nicht, was ein klares Argument dafür ist, bei mehrfacher Verwendung von Flagklassen, diese als Member zu verwenden.

    Und schon wird dein Design inkonsequent - alleinstehende Flags als Basisklasse, kombinierte Flags als Member (und wenn du die Klasse später erweitern willst, mußt du sie komplett umbauen, was nicht gerade angenehm für den Verwender ist). Dann habe ich lieber ein konsequentes Design: Alle Flag's sind Member.



  • CStoll schrieb:

    Aber bei der Variante mit expliziten Flags sieht man, ob man nun das selbe Flag beeinflusst/überschreibt oder nicht:

    vergleich mal:

    dlg = Dialog::Fullscreen;//ist eigentlich WindowFlag::Fullscreen
    dlg = Dialog::Modal;//ist DialogFlag::Modal
    

    vs.

    dlg.wFlag = Fullscreen;
    dlg.dFlag = Modal;
    

    Ehrlich gesagt, benutze ich Klassen, weil mich die Implementierung nach der Implementierung nicht mehr interessiert. Von daher ist mir ehrlich gesagt egal, ob Fullscreen jetzt in wFlag oder dFlag gespeichert wird, solange der Compiler es richtig zuordnen kann.
    Das Objekt wird beeinflusst und das wird korrekt umgesetzt. Mehr interessiert mich nicht. Ich habe keine Lust mir zu merken, ob ich DialogFlag::Modal jetzt dFlag oder wFlag oder xFlag zuordnen muss. Das weiß der Compiler besser als ich.

    CStoll schrieb:

    Kennst du Murphy's Gesetz? Wenn du einen Operator anbietest, wird auch irgendjemand auf die glorreiche Idee kommen, ihn zu verwenden. Und selbst wenn du so diszipliniert bist, nach der Initialisierung des Fensters nur noch über op|= und op& die Flags zu verwenden, wirst du das kaum von jedem deiner Kollegen voraussetzen können.

    Murphys Computergesetze halte ich für das wichtigste Informatik-Fachbuch überhaupt.

    Flags sind Grundlagen. Ich setze Grundlagen grundsätzlich voraus. Und wenn sie nicht da sind, setzt man sich zusammen und erklärt sie. Wenn ich mit Fachinformatikern oder Diplom-Informatikern arbeite, sehe ich es nicht ein, Sourcecodes zu schreiben, die "Hello World"-Niviau haben. Von denen erwarte ich ein Grundverständnis.

    CStoll schrieb:

    Der Unterschied liegt in der Semantik - op& hat eine vordefinierte Bedeutung, die jeder Anwender "versteht" (und bei der man erst einmal überlegen muß, was sie mit dem Problem zu tun hat), HasFlag() drückt durch seinen Namen klar aus, was es für eine Aufgabe hat.
    (und auch auf die Gefahr, mich zu wiederholen, ein Fenster "ist" kein Flag, sondern bestenfalls ein Flagbares Objekt)

    operator & hat bei den Flags eine klare Bedeutung. Ich habe den operator ja nicht aus Spaß ausgewählt oder wie kommst Du darauf, dass derartiges nicht verstanden würde?
    Wie löst Du denn Flags sonst auf? Und erzähl mir jetzt nix von HasFlag...

    Flags sind flagbares Objekte. Fenster sind Flagbare Objekte. Hier besteht eine Verwandtschaft, die man bei guten Design sogar ausnutzen muss.
    Fenster hatten immer Flags (hat ein). Wieviele OS haben wir denn zur Auswahl, die mit OOP arbeiten!?
    Wieviele Programmierer bestehen auf die (hat ein)-Beziehung, nur weil das schon immer so gemacht wurde?

    CStoll schrieb:

    Shade Of Mine schrieb:

    Und dass wir immer noch keine Lösung für

    if(win)
    

    ist auch toll.

    Prüft es ob generell Flags gesetzt sind? Oder prüft es ob das Window in einem "guten" Zustand ist bzw. offen ist?

    Zum Einen: Die Frage habe ich Dir schonmal beantwortet, Du wiederholst Dich.
    Zum anderen: Die Frage ist nicht intelligenter geworden, denn (nochmals) erstens: es ist in der Regel unsinnig 32 unabhängig Fragen gleichzeitig zu stellen und nur abhängig davon zu reagieren, ob alle Fragen die Antwort "Nein" liefern.

    Es ist möglich - und irgendwer wird so clever sein, es auch zu machen (und wenn die Window-Klasse nicht explizit dagegensteuert, wird kein Compiler der Welt so einen Müll verhindern)

    Sorry, das ist nicht mein Job. Wenn ein Entwickler hingeht und für seine "class DeppenWindow : public Window", einen operator bool() implementiert, dann kann und will ich das nicht verhindern.
    Ich implementiere WindowFlags und Window und da wird es keinen operator bool() geben.

    Dass jemand anderer hingehen könnte, und seine Klasse von seinen KlassenFlags ableitet und dabei so einen Mist programmiert, liegt ebenfalls nicht in meiner persönlichen Verantwortung. Man kann vieles verkehrt machen, aber deswegen ist ein richtiger Weg, der einen ähnlichen Weg geht, nicht falsch.

    CStoll schrieb:

    Da sind wir wieder bei der Disziplin der Programmierer - du machst es dir einfach, deine Flag-Klasse zu erstellen. Aber jeder, der irgendwas an deinem Framework machen will, muß die Existenz der Klasse bedenken und ein halbes Dutzend Hilfsmethoden implementieren, die nichts machen außer die Anwendbarkeit dieser Flag-Klasse(n) sicherzustellen.

    Keine Ahnung, wie Du auf ein Dutzend kommst, bei mir geht das recht locker.

    CStoll schrieb:

    So, nun mal ein brauchbares Argument gegen die mehrfache Verwendung von Flag-Klassen. Ich brauchte bisher nicht mehrere davon in einem Objekt. Ich habe eben nochmal damit experimentiert, damit ich mich hier nichts falsches erzähle und folgendes passierte: GCC kompiliert es nicht.

    Die Fehlermeldung lautet: der Operatoraufruf ist mehrdeutig. Er ist aber nicht mehrdeutig, es ist sogar sehr eindeutig. Und der Compiler stimmt mir auch zu, benutzt man globale Operatoren, ist auf einmal alles wieder eindeutig, obwohl der zuvor "mehrdeutige" Code nicht verändert wurde.

    Wenn schon der Compiler dir erklärt, daß du Unsinn baust, solltest du es langsam einsehen 😉

    Der GCC erzählt viel wenn der Tag lang ist und das wäre nicht das erste Mal, dass sich die Geschichte mit der Versionsnummer ändert. Und er ist da nicht der einzige, selbiges gilt für Java, sogar für meinen innig geliebten SAS/C.
    Was das angeht, werde ich mir das im Hinterkopf behalten und bei Gelegenheit mit anderen Compilern testen und versuche die Begründung zu finden, wieso er das für mehrdeutig erklärt, wenn es einen eindeutig passenden und einen eindeutig nicht passenden Operator dafür gibt.
    Was sowas angeht, vertraue ich erstmal auf meinen C++-Compiler im Kopf und der wirft nach eingehender Prüfung immernoch ein OK raus.

    CStoll schrieb:

    Soweit ich weiß, gibt es zwischen den beiden Möglichkeiten, Operatoren zu definieren, keinen semantischen Unterschied. Entweder liege ich da falsch oder der GCC. Grundsätzlich vertraue ich dem Compiler, aber der GCC hätte mein Vertauen nicht zum ersten Mal enttäuscht.

    Es gibt einen Unterschied zwischen beidem - die Art der Überladungs-Auflösung (das kommen bei Methoden die unterschiedlichen Scopes der beteiligten Klassen dazu, die der Compiler auch mit berücksichtigen muß).

    Du weißt nicht zufällig eine detailierte Beschreibung dazu, damit ich gucken kann, ob das auf mein Problem zutrifft und wenn ja, warum.

    CStoll schrieb:

    Ich werde also noch etwas recherchieren, wer von uns beiden hier recht hat. Egal, wer recht hat, der GCC frisst es zur Zeit nicht, was ein klares Argument dafür ist, bei mehrfacher Verwendung von Flagklassen, diese als Member zu verwenden.

    Und schon wird dein Design inkonsequent - alleinstehende Flags als Basisklasse, kombinierte Flags als Member (und wenn du die Klasse später erweitern willst, mußt du sie komplett umbauen, was nicht gerade angenehm für den Verwender ist). Dann habe ich lieber ein konsequentes Design: Alle Flag's sind Member.

    Mein Design wird nicht inkonsequent, mein Design lässt sich mit dem GCC nur dann kompilieren, wenn die Operatoren global definiert sind. Ich selbst, werde eher die Operatoren global definieren, als das Design aufgeben.
    Und ich muss wissen, ob es sich hier um einen Fehler im GCC handelt, oder um ein "Sprachfeature". Wenn es ein Feature ist, muss ich wissen, warum die C++ derartiges einschränkt. Und wenn der Grund gut ist, kann ich das gut akzeptieren.
    Aber da sind noch einige "wenn"s zu klären, bis dahin ist alles Halbwissen und Halbwissen ist wesentlich gefährlicher als ein Design, dass sich nicht kompilieren lässt, weil der Compiler einen Fehler enthält.



  • Xin schrieb:

    CStoll schrieb:

    Aber bei der Variante mit expliziten Flags sieht man, ob man nun das selbe Flag beeinflusst/überschreibt oder nicht:

    vergleich mal:

    dlg = Dialog::Fullscreen;//ist eigentlich WindowFlag::Fullscreen
    dlg = Dialog::Modal;//ist DialogFlag::Modal
    

    vs.

    dlg.wFlag = Fullscreen;
    dlg.dFlag = Modal;
    

    Ehrlich gesagt, benutze ich Klassen, weil mich die Implementierung nach der Implementierung nicht mehr interessiert. Von daher ist mir ehrlich gesagt egal, ob Fullscreen jetzt in wFlag oder dFlag gespeichert wird, solange der Compiler es richtig zuordnen kann.

    Dir ist es vielleicht egal, aber ich will schon gerne wissen, welche Flags-Zuweisungen sich jetzt gegenseitig beeinflussen. Und bei der oberen Variante muß man erst die Herkunft der Bezeichner heraussuchen, um zu erkennen, ob die Sequenz erlaubt ist oder nicht.

    CStoll schrieb:

    Kennst du Murphy's Gesetz? Wenn du einen Operator anbietest, wird auch irgendjemand auf die glorreiche Idee kommen, ihn zu verwenden. Und selbst wenn du so diszipliniert bist, nach der Initialisierung des Fensters nur noch über op|= und op& die Flags zu verwenden, wirst du das kaum von jedem deiner Kollegen voraussetzen können.

    Murphys Computergesetze halte ich für das wichtigste Informatik-Fachbuch überhaupt.

    Flags sind Grundlagen. Ich setze Grundlagen grundsätzlich voraus. Und wenn sie nicht da sind, setzt man sich zusammen und erklärt sie. Wenn ich mit Fachinformatikern oder Diplom-Informatikern arbeite, sehe ich es nicht ein, Sourcecodes zu schreiben, die "Hello World"-Niviau haben. Von denen erwarte ich ein Grundverständnis.

    "Flags" als Konzept sind Grundlagen, dein Verständnis von Flags ist dagegen erklärungsbedürftig.

    CStoll schrieb:

    Der Unterschied liegt in der Semantik - op& hat eine vordefinierte Bedeutung, die jeder Anwender "versteht" (und bei der man erst einmal überlegen muß, was sie mit dem Problem zu tun hat), HasFlag() drückt durch seinen Namen klar aus, was es für eine Aufgabe hat.
    (und auch auf die Gefahr, mich zu wiederholen, ein Fenster "ist" kein Flag, sondern bestenfalls ein Flagbares Objekt)

    operator & hat bei den Flags eine klare Bedeutung. Ich habe den operator ja nicht aus Spaß ausgewählt oder wie kommst Du darauf, dass derartiges nicht verstanden würde?
    Wie löst Du denn Flags sonst auf? Und erzähl mir jetzt nix von HasFlag...

    Ich kombiniere Flags schon über & und |, wenn ich das brauche, aber ich leite die Klassen, die damit arbeiten, nicht von der Flag-Klasse ab.

    Flags sind flagbares Objekte. Fenster sind Flagbare Objekte. Hier besteht eine Verwandtschaft, die man bei guten Design sogar ausnutzen muss.
    Fenster hatten immer Flags (hat ein). Wieviele OS haben wir denn zur Auswahl, die mit OOP arbeiten!?

    Nein, Flags sind nicht flagbar, bestenfalls kombinierbar. Und eine "hat-ein" Beziehung wird nicht durch öffentliche Vererbung abgebildet.

    CStoll schrieb:

    Shade Of Mine schrieb:

    Und dass wir immer noch keine Lösung für

    if(win)
    

    ist auch toll.

    Prüft es ob generell Flags gesetzt sind? Oder prüft es ob das Window in einem "guten" Zustand ist bzw. offen ist?

    Zum Einen: Die Frage habe ich Dir schonmal beantwortet, Du wiederholst Dich.
    Zum anderen: Die Frage ist nicht intelligenter geworden, denn (nochmals) erstens: es ist in der Regel unsinnig 32 unabhängig Fragen gleichzeitig zu stellen und nur abhängig davon zu reagieren, ob alle Fragen die Antwort "Nein" liefern.

    Es ist möglich - und irgendwer wird so clever sein, es auch zu machen (und wenn die Window-Klasse nicht explizit dagegensteuert, wird kein Compiler der Welt so einen Müll verhindern)

    Sorry, das ist nicht mein Job. Wenn ein Entwickler hingeht und für seine "class DeppenWindow : public Window", einen operator bool() implementiert, dann kann und will ich das nicht verhindern.

    WindowFlag hat/braucht einen 'operator bool' (oder vergleichbares), sonst kannst du deine Aufrufe "if(wnd&Window::Fullscreen);" nicht umsetzen - und solange abgeleitete Klassen den nicht (privat) überschreiben, erben sie diesen Operator.

    Ich implementiere WindowFlags und Window und da wird es keinen operator bool() geben.

    Was dann? Bzw. wie willst du sonst einzelne Flags abfragen?

    Dass jemand anderer hingehen könnte, und seine Klasse von seinen KlassenFlags ableitet und dabei so einen Mist programmiert, liegt ebenfalls nicht in meiner persönlichen Verantwortung. Man kann vieles verkehrt machen, aber deswegen ist ein richtiger Weg, der einen ähnlichen Weg geht, nicht falsch.

    Wieso setzt du dann einen halb ausgereiften Ansatz hierhin, wenn du doch niemanden davon profitieren lassen willst? Du stellst hier ein Grundgerüst zur Verfügung und andere Programmierer erwarten, daß dieses ohne größere Komplikationen (und wenn's geht, ohne überhaupt beachtet zu werden) verwendet werden kann.

    CStoll schrieb:

    Da sind wir wieder bei der Disziplin der Programmierer - du machst es dir einfach, deine Flag-Klasse zu erstellen. Aber jeder, der irgendwas an deinem Framework machen will, muß die Existenz der Klasse bedenken und ein halbes Dutzend Hilfsmethoden implementieren, die nichts machen außer die Anwendbarkeit dieser Flag-Klasse(n) sicherzustellen.

    Keine Ahnung, wie Du auf ein Dutzend kommst, bei mir geht das recht locker.

    Grob geschätzt - die Blattklassen brauchen auf jeden Fall einen op= für jede Flag-Klasse, die weiter oben in der Hierarchie verwendet wurde (der Compiler erzeugt deinen eigenen op= und überdeckt damit alle eventuell geerbten) und einen privaten operator bool(), um Anweisungen wie "if(win)..." abzufangen, was sonst noch nötig ist, will ich gar nicht wissen.

    CStoll schrieb:

    So, nun mal ein brauchbares Argument gegen die mehrfache Verwendung von Flag-Klassen. Ich brauchte bisher nicht mehrere davon in einem Objekt. Ich habe eben nochmal damit experimentiert, damit ich mich hier nichts falsches erzähle und folgendes passierte: GCC kompiliert es nicht.

    Die Fehlermeldung lautet: der Operatoraufruf ist mehrdeutig. Er ist aber nicht mehrdeutig, es ist sogar sehr eindeutig. Und der Compiler stimmt mir auch zu, benutzt man globale Operatoren, ist auf einmal alles wieder eindeutig, obwohl der zuvor "mehrdeutige" Code nicht verändert wurde.

    Wenn schon der Compiler dir erklärt, daß du Unsinn baust, solltest du es langsam einsehen 😉

    Der GCC erzählt viel wenn der Tag lang ist und das wäre nicht das erste Mal, dass sich die Geschichte mit der Versionsnummer ändert. Und er ist da nicht der einzige, selbiges gilt für Java, sogar für meinen innig geliebten SAS/C.
    Was das angeht, werde ich mir das im Hinterkopf behalten und bei Gelegenheit mit anderen Compilern testen und versuche die Begründung zu finden, wieso er das für mehrdeutig erklärt, wenn es einen eindeutig passenden und einen eindeutig nicht passenden Operator dafür gibt.

    Was sowas angeht, vertraue ich erstmal auf meinen C++-Compiler im Kopf und der wirft nach eingehender Prüfung immernoch ein OK raus.

    Ich bin inzwischen zu der Erkenntnis gekommen, daß die heutigen Compiler mehr von Standard C++ verstehen als ich - und deshalb dürfte ein Fehler zu 99% auf deiner Seite liegen (es sei denn, du kennst den ANSI-Standard auswendig).

    CStoll schrieb:

    Soweit ich weiß, gibt es zwischen den beiden Möglichkeiten, Operatoren zu definieren, keinen semantischen Unterschied. Entweder liege ich da falsch oder der GCC. Grundsätzlich vertraue ich dem Compiler, aber der GCC hätte mein Vertauen nicht zum ersten Mal enttäuscht.

    Es gibt einen Unterschied zwischen beidem - die Art der Überladungs-Auflösung (das kommen bei Methoden die unterschiedlichen Scopes der beteiligten Klassen dazu, die der Compiler auch mit berücksichtigen muß).

    Du weißt nicht zufällig eine detailierte Beschreibung dazu, damit ich gucken kann, ob das auf mein Problem zutrifft und wenn ja, warum.

    Leider nein, aber versuch's mal im Standard.
    (ohne Garantie: Bei der Überladungsauflösung wird zuerst der Scope gesucht, der in Frage kommen könnte und danach aus allen Funktionen aus diesem Scope die ausgewählt, die am besten passt - bei dir dürfte schon der erste Schritt scheitern)

    CStoll schrieb:

    Ich werde also noch etwas recherchieren, wer von uns beiden hier recht hat. Egal, wer recht hat, der GCC frisst es zur Zeit nicht, was ein klares Argument dafür ist, bei mehrfacher Verwendung von Flagklassen, diese als Member zu verwenden.

    Und schon wird dein Design inkonsequent - alleinstehende Flags als Basisklasse, kombinierte Flags als Member (und wenn du die Klasse später erweitern willst, mußt du sie komplett umbauen, was nicht gerade angenehm für den Verwender ist). Dann habe ich lieber ein konsequentes Design: Alle Flag's sind Member.

    Mein Design wird nicht inkonsequent, mein Design lässt sich mit dem GCC nur dann kompilieren, wenn die Operatoren global definiert sind. Ich selbst, werde eher die Operatoren global definieren, als das Design aufgeben.
    Und ich muss wissen, ob es sich hier um einen Fehler im GCC handelt, oder um ein "Sprachfeature". Wenn es ein Feature ist, muss ich wissen, warum die C++ derartiges einschränkt. Und wenn der Grund gut ist, kann ich das gut akzeptieren.
    Aber da sind noch einige "wenn"s zu klären, bis dahin ist alles Halbwissen und Halbwissen ist wesentlich gefährlicher als ein Design, dass sich nicht kompilieren lässt, weil der Compiler einen Fehler enthält.

    Oder ein Design, das einfach von der falschen Seite an ein Problem herangeht 😉



  • so gehts natürlich auch, erst dämlich anpflaumen und dann rumkneifen 🙄



  • CStoll schrieb:

    Xin schrieb:

    CStoll schrieb:

    Aber bei der Variante mit expliziten Flags sieht man, ob man nun das selbe Flag beeinflusst/überschreibt oder nicht:

    vergleich mal:

    dlg = Dialog::Fullscreen;//ist eigentlich WindowFlag::Fullscreen
    dlg = Dialog::Modal;//ist DialogFlag::Modal
    

    vs.

    dlg.wFlag = Fullscreen;
    dlg.dFlag = Modal;
    

    Ehrlich gesagt, benutze ich Klassen, weil mich die Implementierung nach der Implementierung nicht mehr interessiert. Von daher ist mir ehrlich gesagt egal, ob Fullscreen jetzt in wFlag oder dFlag gespeichert wird, solange der Compiler es richtig zuordnen kann.

    Dir ist es vielleicht egal, aber ich will schon gerne wissen, welche Flags-Zuweisungen sich jetzt gegenseitig beeinflussen. Und bei der oberen Variante muß man erst die Herkunft der Bezeichner heraussuchen, um zu erkennen, ob die Sequenz erlaubt ist oder nicht.

    Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.

    CStoll schrieb:

    Flags sind Grundlagen. Ich setze Grundlagen grundsätzlich voraus. Und wenn sie nicht da sind, setzt man sich zusammen und erklärt sie. Wenn ich mit Fachinformatikern oder Diplom-Informatikern arbeite, sehe ich es nicht ein, Sourcecodes zu schreiben, die "Hello World"-Niviau haben. Von denen erwarte ich ein Grundverständnis.

    "Flags" als Konzept sind Grundlagen, dein Verständnis von Flags ist dagegen erklärungsbedürftig.

    Flags sind Flags. Ich gehe eigentlich davon aus, kein erklärungsbedürftiges Verständnis davon zu haben.

    CStoll schrieb:

    CStoll schrieb:

    Der Unterschied liegt in der Semantik - op& hat eine vordefinierte Bedeutung, die jeder Anwender "versteht" (und bei der man erst einmal überlegen muß, was sie mit dem Problem zu tun hat), HasFlag() drückt durch seinen Namen klar aus, was es für eine Aufgabe hat.
    (und auch auf die Gefahr, mich zu wiederholen, ein Fenster "ist" kein Flag, sondern bestenfalls ein Flagbares Objekt)

    operator & hat bei den Flags eine klare Bedeutung. Ich habe den operator ja nicht aus Spaß ausgewählt oder wie kommst Du darauf, dass derartiges nicht verstanden würde?
    Wie löst Du denn Flags sonst auf? Und erzähl mir jetzt nix von HasFlag...

    Ich kombiniere Flags schon über & und |

    Dann sind die Operatoren doch semantisch sinnvoll gewählt.

    CStoll schrieb:

    Flags sind flagbares Objekte. Fenster sind Flagbare Objekte. Hier besteht eine Verwandtschaft, die man bei guten Design sogar ausnutzen muss.
    Fenster hatten immer Flags (hat ein). Wieviele OS haben wir denn zur Auswahl, die mit OOP arbeiten!?

    Nein, Flags sind nicht flagbar, bestenfalls kombinierbar.

    Die Klasse Flags ist flagbar. Genau das ist ihre Funktion.

    CStoll schrieb:

    Ich implementiere WindowFlags und Window und da wird es keinen operator bool() geben.

    Was dann? Bzw. wie willst du sonst einzelne Flags abfragen?

    Die Frage ist gut... ^^
    Die Frage ist sogar so gut, dass ich mir meine Implementierung ansehen musste, weil hier irgendwas sonst nicht passen kann...
    Und da steht: in C++ habe ich einen operator bool().

    Wenn ich einen Rückzieher mache, dann mache ich das deutlicher, das sieht dann ungefähr so aus:
    Was den operator bool() angeht, habe ich mich zu weit aus dem Fenster gelehnt, weil ich hier was durcheinander geworfen habe und es jetzt auch schon wieder einige Zeit her ist, seitdem ich die Flagklassen entworfen habe.
    Ergo gilt auch das Argument von Shade, bzgl. if( win ). Ein offizielles und ernstgemeines Sorry an ihn und einen nicht ganz so ernstgemeinten Kniefall. 😉

    Wie kam ich darauf, dass ich den operator bool() verleugnete?
    Ich habe das Konzept von Genesys auf C++ übertragen, was aber so nicht geht, also habe ich in C++ operator bool() genau aus dem Grund überladen müssen. In Genesys (die Sprache, die ich entwickle) gibt es nicht nur Typen, sondern auch Typerweiterungen, die man an andere Typen anhängen kann. Die Flags ist eine solche Typerwerweiterung. Eine Erweiterung wird ge- und vererbt. Es handelt sich dabei aber um keine Form, die teilweise private, teilweise public ist. Die Kombination aus einer Klasse mit Flags überlädt nicht den einfachen operator bool(), sondern eine Kombination von Operatoren, so dass für if( win ) kein operator bool() definiert ist, für if( win & WindowFlag::Fullscreen ) die Sache aber anders aussieht.

    Diese Typerweiterungen haben ihren eigenen Namen, z.B. WindowFlags und deren Member werden nicht in den Namensraum übernommen. Window::Fullscreen existiert hier nicht, man muss also wirklich win |= WindowFlags::FullScreen schreiben.

    CStoll schrieb:

    Dass jemand anderer hingehen könnte, und seine Klasse von seinen KlassenFlags ableitet und dabei so einen Mist programmiert, liegt ebenfalls nicht in meiner persönlichen Verantwortung. Man kann vieles verkehrt machen, aber deswegen ist ein richtiger Weg, der einen ähnlichen Weg geht, nicht falsch.

    Wieso setzt du dann einen halb ausgereiften Ansatz hierhin, wenn du doch niemanden davon profitieren lassen willst? Du stellst hier ein Grundgerüst zur Verfügung und andere Programmierer erwarten, daß dieses ohne größere Komplikationen (und wenn's geht, ohne überhaupt beachtet zu werden) verwendet werden kann.

    Ich biete eine Alternative an. Die Alternative steht immernoch und sie funktioniert. Sie bedarf in C++ mehr Disziplin, als ich annahm, als ich das Posting schrieb, aber sie ist immernoch sinnvoll, auch dann, wenn operator bool() durchläuft, denn er ist aus der Vererbungshirachie zu erkennen.

    Ich schreibe hier ein Posting als Antwort auf eine Frage. Ich mache keine Doktorarbeit daraus. Und wenn ich hier Quelltext sehe, dann erwarte ich hier definitiv nicht, dass ich den einfach blind kopieren kann. Ich erwarte hier Anregung und Antworten, aber definitiv keine fertigen Lösungen.

    CStoll schrieb:

    Ich bin inzwischen zu der Erkenntnis gekommen, daß die heutigen Compiler mehr von Standard C++ verstehen als ich - und deshalb dürfte ein Fehler zu 99% auf deiner Seite liegen (es sei denn, du kennst den ANSI-Standard auswendig).

    Nein, auswendig kenne ich ihn nicht. Aber der Standard ist eine wohlüberlegte Sache und die Antwort des Compilers erscheint mir nur bedingt wohlüberlegt - in jedem Fall ist die Fehlermeldung vollkommen unpassend. Also habe ich entweder einen Aspekt der Überlegung übersehen oder es liegt ein Compilerfehler vor.
    Falls der Fehler an mir liegt, muss ich den Grund erfahren, um zu verstehen, warum das nicht geht. Anderenfalls muss ich wissen, dass es ein Compilerfehler ist, um sicher zu sein, dass es nicht an mir liegt.

    CStoll schrieb:

    (ohne Garantie: Bei der Überladungsauflösung wird zuerst der Scope gesucht, der in Frage kommen könnte und danach aus allen Funktionen aus diesem Scope die ausgewählt, die am besten passt - bei dir dürfte schon der erste Schritt scheitern)

    Zwei operator &-Funktionen stehen zur Auswahl. Eine Signatur passt perfekt, die andere passt überhaupt nicht.
    Und der Aufruf soll mehrdeutig sein.
    Das sagt mir auf jedenfall, dass die beide Operatoren zur Verfügung stehen und dass es ein Problem gibt zwei unterschiedliche Klassentypen auseinander zu halten, wobei nichtmals auf eine Basisklasse konvertiert werden müsste, weil der gegebene Typ explizit in der Signatur genannt wird.
    Es spielt keine Rolle, ob das mit operatoren oder normalen Funktionen probiert wird.
    Ebenfalls ist es mehrdeutig, wenn ich die Funktion mit einem "int" aufrufe und genau eine Funktion mit "int" in der Signatur habe. Der Compiler ist also nicht in der Lage ein "int" von "WindowFlag &" oder "WindowMode &" zu unterscheiden. Es ist also kein Problem, dass daher kommt, dass WindowFlag und WindowMode eine gemeinsame Basisklasse haben.

    Das Problem wird also daher kommen, dass die Überladung durch Mehrfachvererbung zustande gekommen ist.
    Und dann stellt sich die Frage, ob im GCC die Überladung durch Mehrfachererbung entweder nicht richtig implementiert wurde oder ob es eine begründete Regel gibt, derartig eindeutige Funktions-Überladungen grundsätzlich zu verbieten, selbst wenn sie eindeutig sind.
    Wäre die Qualifizierung - z.B. "WindowFlag::" - notwendig, so wäre die Fehlermeldung sinnvoll, wenn zwei identische Signaturen durch die Mehrfachvererbung zusammenkommen. Das Problem tritt hier aber nicht auf.
    Entweder nimmt der GCC die Sache zu genau - oder ich nehme die Sache zu locker.
    Dann bleibt die Frage, wer mit seiner Ansicht besser liegt.

    Viele offene Fragen...



  • Xin schrieb:

    CStoll schrieb:

    Xin schrieb:

    CStoll schrieb:

    Aber bei der Variante mit expliziten Flags sieht man, ob man nun das selbe Flag beeinflusst/überschreibt oder nicht:

    vergleich mal:

    dlg = Dialog::Fullscreen;//ist eigentlich WindowFlag::Fullscreen
    dlg = Dialog::Modal;//ist DialogFlag::Modal
    

    vs.

    dlg.wFlag = Fullscreen;
    dlg.dFlag = Modal;
    

    Ehrlich gesagt, benutze ich Klassen, weil mich die Implementierung nach der Implementierung nicht mehr interessiert. Von daher ist mir ehrlich gesagt egal, ob Fullscreen jetzt in wFlag oder dFlag gespeichert wird, solange der Compiler es richtig zuordnen kann.

    Dir ist es vielleicht egal, aber ich will schon gerne wissen, welche Flags-Zuweisungen sich jetzt gegenseitig beeinflussen. Und bei der oberen Variante muß man erst die Herkunft der Bezeichner heraussuchen, um zu erkennen, ob die Sequenz erlaubt ist oder nicht.

    Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.

    Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.

    CStoll schrieb:

    Flags sind Grundlagen. Ich setze Grundlagen grundsätzlich voraus. Und wenn sie nicht da sind, setzt man sich zusammen und erklärt sie. Wenn ich mit Fachinformatikern oder Diplom-Informatikern arbeite, sehe ich es nicht ein, Sourcecodes zu schreiben, die "Hello World"-Niviau haben. Von denen erwarte ich ein Grundverständnis.

    "Flags" als Konzept sind Grundlagen, dein Verständnis von Flags ist dagegen erklärungsbedürftig.

    Flags sind Flags. Ich gehe eigentlich davon aus, kein erklärungsbedürftiges Verständnis davon zu haben.

    Eben nicht. "Flags" als abtraktes Konzept sind (denke ich) jedem halbwegs erfahrenen Programmierer bekannt. Aber deine Sichtweise von Flags (und die Art, wie du sie umsetzt) - SIND erklärungsbedürftig (glaub's mir ruhig).

    CStoll schrieb:

    CStoll schrieb:

    Der Unterschied liegt in der Semantik - op& hat eine vordefinierte Bedeutung, die jeder Anwender "versteht" (und bei der man erst einmal überlegen muß, was sie mit dem Problem zu tun hat), HasFlag() drückt durch seinen Namen klar aus, was es für eine Aufgabe hat.
    (und auch auf die Gefahr, mich zu wiederholen, ein Fenster "ist" kein Flag, sondern bestenfalls ein Flagbares Objekt)

    operator & hat bei den Flags eine klare Bedeutung. Ich habe den operator ja nicht aus Spaß ausgewählt oder wie kommst Du darauf, dass derartiges nicht verstanden würde?
    Wie löst Du denn Flags sonst auf? Und erzähl mir jetzt nix von HasFlag...

    Ich kombiniere Flags schon über & und |

    Dann sind die Operatoren doch semantisch sinnvoll gewählt.

    Auch auf die Gefahr hin, mich zu wiederholen: An den Operatoren habe ich nichts auszusetzen - nur an der Vererbungsbeziehung (aber du kannst es dir gerne leicht machen, und meine Sätze nur bis zur Hälfte lesen :D).

    CStoll schrieb:

    Flags sind flagbares Objekte. Fenster sind Flagbare Objekte. Hier besteht eine Verwandtschaft, die man bei guten Design sogar ausnutzen muss.
    Fenster hatten immer Flags (hat ein). Wieviele OS haben wir denn zur Auswahl, die mit OOP arbeiten!?

    Nein, Flags sind nicht flagbar, bestenfalls kombinierbar.

    Die Klasse Flags ist flagbar. Genau das ist ihre Funktion.

    Kannst du in einem Flag andere Flags setzen? Nein. Ein Flag ist eine Marke, die aussagt, ob etwas eine bestimmte Eigenschaft hat. Dieses etwas ist vielleicht flagbar, aber nicht das flag selber.
    (oder willst du mir auch erzählen, daß eine Farbe färbbar ist?)

    *grübelt* und so langsam glaube ich, daß bei dir sogar das Konzept "Flag" unklar ist.

    CStoll schrieb:

    Ich implementiere WindowFlags und Window und da wird es keinen operator bool() geben.

    Was dann? Bzw. wie willst du sonst einzelne Flags abfragen?

    Die Frage ist gut... ^^
    Die Frage ist sogar so gut, dass ich mir meine Implementierung ansehen musste, weil hier irgendwas sonst nicht passen kann...
    Und da steht: in C++ habe ich einen operator bool().

    Wenn ich einen Rückzieher mache, dann mache ich das deutlicher, das sieht dann ungefähr so aus:
    Was den operator bool() angeht, habe ich mich zu weit aus dem Fenster gelehnt, weil ich hier was durcheinander geworfen habe und es jetzt auch schon wieder einige Zeit her ist, seitdem ich die Flagklassen entworfen habe.
    Ergo gilt auch das Argument von Shade, bzgl. if( win ). Ein offizielles und ernstgemeines Sorry an ihn und einen nicht ganz so ernstgemeinten Kniefall. 😉

    Da siehst du es - noch nicht einmal du selber weißt, was man mit deinen Flag-Klassen machen kann. Wie soll da noch ein anderer Programmierer, der nur deinen Code sieht, da durchblicken?

    Wie kam ich darauf, dass ich den operator bool() verleugnete?
    Ich habe das Konzept von Genesys auf C++ übertragen, was aber so nicht geht, also habe ich in C++ operator bool() genau aus dem Grund überladen müssen. In Genesys (die Sprache, die ich entwickle) gibt es nicht nur Typen, sondern auch Typerweiterungen, die man an andere Typen anhängen kann. Die Flags ist eine solche Typerwerweiterung. Eine Erweiterung wird ge- und vererbt. Es handelt sich dabei aber um keine Form, die teilweise private, teilweise public ist. Die Kombination aus einer Klasse mit Flags überlädt nicht den einfachen operator bool(), sondern eine Kombination von Operatoren, so dass für if( win ) kein operator bool() definiert ist, für if( win & WindowFlag::Fullscreen ) die Sache aber anders aussieht.

    Tja, C++ Vererbung ist halt etwas anderes als diese Typerweiterung. Und wenn du gewaltsam versuchst, ein Konzept in einer anderen Sprache nachzubilden, schaffst du damit nur Probleme. (das sieht man hier immer wieder, wenn Java-Programmierer mit C++ anfangen - oder umgekehrt)

    CStoll schrieb:

    Dass jemand anderer hingehen könnte, und seine Klasse von seinen KlassenFlags ableitet und dabei so einen Mist programmiert, liegt ebenfalls nicht in meiner persönlichen Verantwortung. Man kann vieles verkehrt machen, aber deswegen ist ein richtiger Weg, der einen ähnlichen Weg geht, nicht falsch.

    Wieso setzt du dann einen halb ausgereiften Ansatz hierhin, wenn du doch niemanden davon profitieren lassen willst? Du stellst hier ein Grundgerüst zur Verfügung und andere Programmierer erwarten, daß dieses ohne größere Komplikationen (und wenn's geht, ohne überhaupt beachtet zu werden) verwendet werden kann.

    Ich biete eine Alternative an. Die Alternative steht immernoch und sie funktioniert. Sie bedarf in C++ mehr Disziplin, als ich annahm, als ich das Posting schrieb, aber sie ist immernoch sinnvoll, auch dann, wenn operator bool() durchläuft, denn er ist aus der Vererbungshirachie zu erkennen.

    Ja, deine Alternative mag ja in Genesys der richtige Weg sein, aber in C++ ist sie immer noch falsch.

    Ich schreibe hier ein Posting als Antwort auf eine Frage. Ich mache keine Doktorarbeit daraus. Und wenn ich hier Quelltext sehe, dann erwarte ich hier definitiv nicht, dass ich den einfach blind kopieren kann. Ich erwarte hier Anregung und Antworten, aber definitiv keine fertigen Lösungen.

    Dann hoffe ich für dich, daß deine produktiven Quelltexte reichlich mit Dokumentationen versehen sind, was man mit den Klassen machen darf und was nicht (und was den Nutzer erwartet, wenn er sich nicht daran hält).

    CStoll schrieb:

    Ich bin inzwischen zu der Erkenntnis gekommen, daß die heutigen Compiler mehr von Standard C++ verstehen als ich - und deshalb dürfte ein Fehler zu 99% auf deiner Seite liegen (es sei denn, du kennst den ANSI-Standard auswendig).

    Nein, auswendig kenne ich ihn nicht. Aber der Standard ist eine wohlüberlegte Sache und die Antwort des Compilers erscheint mir nur bedingt wohlüberlegt - in jedem Fall ist die Fehlermeldung vollkommen unpassend. Also habe ich entweder einen Aspekt der Überlegung übersehen oder es liegt ein Compilerfehler vor.
    Falls der Fehler an mir liegt, muss ich den Grund erfahren, um zu verstehen, warum das nicht geht. Anderenfalls muss ich wissen, dass es ein Compilerfehler ist, um sicher zu sein, dass es nicht an mir liegt.

    CStoll schrieb:

    (ohne Garantie: Bei der Überladungsauflösung wird zuerst der Scope gesucht, der in Frage kommen könnte und danach aus allen Funktionen aus diesem Scope die ausgewählt, die am besten passt - bei dir dürfte schon der erste Schritt scheitern)

    Zwei operator &-Funktionen stehen zur Auswahl. Eine Signatur passt perfekt, die andere passt überhaupt nicht.
    Und der Aufruf soll mehrdeutig sein.

    Nicht ganz - die Funktion Window hat keinen einzigen operator& - aber es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, die passen könnten.

    Das Problem wird also daher kommen, dass die Überladung durch Mehrfachvererbung zustande gekommen ist.
    Und dann stellt sich die Frage, ob im GCC die Überladung durch Mehrfachererbung entweder nicht richtig implementiert wurde oder ob es eine begründete Regel gibt, derartig eindeutige Funktions-Überladungen grundsätzlich zu verbieten, selbst wenn sie eindeutig sind.

    Soweit ich weiß, letzteres. Aber das müsste ich auch nachschlagen.



  • Hallo CStoll,

    könntest Du statt "quote" "quote=werauchimmer" schreiben und bitte zwischen den Absätzen eine Leerzeile einfügen? Es ist ziemlich schwierig in einem Klumpen Text die Stelle zu suchen, wo man eine Antwort zwischenfügen möchte. Eine Leerzeile zwischen den Quotes hilft da ungemein. Ohne die Suchfunktion geht bei Deinen Antworten leider gar nix. Versuch bevor Du auf dieses Posting antwortest mal (ohne Abschicken) Dein Posting zu zitieren und die Stellen zu finden, wo andere Leute antworten würden. Du wirst die Zwischenzeile danach bei mir zu schätzen wissen 😉

    CStoll schrieb:

    Xin schrieb:

    Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.

    Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.

    Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.

    CStoll schrieb:

    CStoll schrieb:

    Ich kombiniere Flags schon über & und |

    Dann sind die Operatoren doch semantisch sinnvoll gewählt.

    Auch auf die Gefahr hin, mich zu wiederholen: An den Operatoren habe ich nichts auszusetzen - nur an der Vererbungsbeziehung (aber du kannst es dir gerne leicht machen, und meine Sätze nur bis zur Hälfte lesen :D).

    Ich habe Deine Kritik durchaus gelesen, zur Kenntnis genommen und das Thema ist subjektiver Natur. Also was soll ich dazu noch schreiben? Es gibt gute Gründe für Vererbung, wie es gute Gründe gegen Vererbung gibt.
    Du kritisiertest auch die Wahl der Operatoren, weil die ja keiner verstehen würde und wolltest HasFlags() usw. haben. Das kommentierte ich - dafür brauche ich den Rest nicht zu quoten.

    CStoll schrieb:

    CStoll schrieb:

    Nein, Flags sind nicht flagbar, bestenfalls kombinierbar.

    Die Klasse Flags ist flagbar. Genau das ist ihre Funktion.

    Kannst du in einem Flag andere Flags setzen? Nein. Ein Flag ist eine Marke, die aussagt, ob etwas eine bestimmte Eigenschaft hat. Dieses etwas ist vielleicht flagbar, aber nicht das flag selber.

    Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.

    CStoll schrieb:

    Wenn ich einen Rückzieher mache, dann mache ich das deutlicher, das sieht dann ungefähr so aus:
    Was den operator bool() angeht, habe ich mich zu weit aus dem Fenster gelehnt, weil ich hier was durcheinander geworfen habe und es jetzt auch schon wieder einige Zeit her ist, seitdem ich die Flagklassen entworfen habe.
    Ergo gilt auch das Argument von Shade, bzgl. if( win ). Ein offizielles und ernstgemeines Sorry an ihn und einen nicht ganz so ernstgemeinten Kniefall. 😉

    Da siehst du es - noch nicht einmal du selber weißt, was man mit deinen Flag-Klassen machen kann. Wie soll da noch ein anderer Programmierer, der nur deinen Code sieht, da durchblicken?

    *lach*, ich habe die Klasse jetzt seit locker einem Jahr nicht mehr angeguckt. Sie funktioniert einwandtfrei. Das Problem ist nicht, dass ich da nicht durchblicke, sondern dass ich derzeit in zwei ähnlichen Sprachwelten hänge.

    CStoll schrieb:

    Dann hoffe ich für dich, daß deine produktiven Quelltexte reichlich mit Dokumentationen versehen sind, was man mit den Klassen machen darf und was nicht (und was den Nutzer erwartet, wenn er sich nicht daran hält).

    Aufwendige Algorithmen werden selbstverständlich durchdokumentiert.

    Auch meine Klassen sind mit Doxygen dokumentiert. Aber nicht, weil sie nicht intuitiv wären, sondern weil es soviele sind, dass ich nicht immer alles im Kopf halten kann. Muss man irgendwo etwas ändern, wo man ein paar Jahre nicht mehr vorbeigeschaut hat, so ist die Dokumentation hilfreich.

    CStoll schrieb:

    Zwei operator &-Funktionen stehen zur Auswahl. Eine Signatur passt perfekt, die andere passt überhaupt nicht.
    Und der Aufruf soll mehrdeutig sein.

    Nicht ganz - die Funktion Window hat keinen einzigen operator& - aber es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, die passen könnten.

    Das kann nicht die Erklärung sein, denn das würde die Verwendung von vererbten Funktionen jeglicher Art verhindern. Es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, von denen aber eine überhaupt nicht passt und eine genau passt.
    Dass die Sprache sich unsicher gibt, ist in Ordnung, aber es ist definitiv nicht mehrdeutig. Es liegt definitiv ein Compilerfehler vor. Selbst wenn die Geschichte programmiersprachlich korrekt umgesetzt wurde, so liegt zumindest eine unsaubere Fehlermeldung vor, was ebenfalls ein Compilerfehler ist.



  • Xin schrieb:

    Hallo CStoll,

    könntest Du statt "quote" "quote=werauchimmer" schreiben und bitte zwischen den Absätzen eine Leerzeile einfügen? Es ist ziemlich schwierig in einem Klumpen Text die Stelle zu suchen, wo man eine Antwort zwischenfügen möchte. Eine Leerzeile zwischen den Quotes hilft da ungemein. Ohne die Suchfunktion geht bei Deinen Antworten leider gar nix. Versuch bevor Du auf dieses Posting antwortest mal (ohne Abschicken) Dein Posting zu zitieren und die Stellen zu finden, wo andere Leute antworten würden. Du wirst die Zwischenzeile danach bei mir zu schätzen wissen 😉

    OK, ich werde mich in Zukunft bemühen.

    Xin schrieb:

    CStoll schrieb:

    Xin schrieb:

    Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.

    Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.

    Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.

    Ich will es aber an dem Ort wissen, wo ich die Flags verwende - dem Code

    dlg = Dialog::Fullscreen;
    dlg = Dialog::Modal;
    

    sieht man nicht an, ob der Dialog hinterher noch im Vollbild-Modus ist oder nicht (und selbst mit expliziten Angaben WindowFlag::Fullscreen bzw. DialogFlag::Modal mußt du erstmal nachsehen, welchen Typ beides hat - ein Anwender könnte durchaus auf die Idee kommen, die DialogFlag-Klasse nur als Sammlung von zusätzlichen WindowFlag-Werten anzulegen).

    Xin schrieb:

    CStoll schrieb:

    CStoll schrieb:

    Ich kombiniere Flags schon über & und |

    Dann sind die Operatoren doch semantisch sinnvoll gewählt.

    Auch auf die Gefahr hin, mich zu wiederholen: An den Operatoren habe ich nichts auszusetzen - nur an der Vererbungsbeziehung (aber du kannst es dir gerne leicht machen, und meine Sätze nur bis zur Hälfte lesen :D).

    Ich habe Deine Kritik durchaus gelesen, zur Kenntnis genommen und das Thema ist subjektiver Natur. Also was soll ich dazu noch schreiben? Es gibt gute Gründe für Vererbung, wie es gute Gründe gegen Vererbung gibt.
    Du kritisiertest auch die Wahl der Operatoren, weil die ja keiner verstehen würde und wolltest HasFlags() usw. haben. Das kommentierte ich - dafür brauche ich den Rest nicht zu quoten.

    Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.

    Xin schrieb:

    CStoll schrieb:

    CStoll schrieb:

    Nein, Flags sind nicht flagbar, bestenfalls kombinierbar.

    Die Klasse Flags ist flagbar. Genau das ist ihre Funktion.

    Kannst du in einem Flag andere Flags setzen? Nein. Ein Flag ist eine Marke, die aussagt, ob etwas eine bestimmte Eigenschaft hat. Dieses etwas ist vielleicht flagbar, aber nicht das flag selber.

    Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.

    Wenn du das aus dieser Sicht siehst, dann sollten die konkreten Flag-Werte aber keine Objekte der Klasse "Flags" sein - diese präsentieren nämlich ein einzelnes Flag.

    Xin schrieb:

    CStoll schrieb:

    Wenn ich einen Rückzieher mache, dann mache ich das deutlicher, das sieht dann ungefähr so aus:
    Was den operator bool() angeht, habe ich mich zu weit aus dem Fenster gelehnt, weil ich hier was durcheinander geworfen habe und es jetzt auch schon wieder einige Zeit her ist, seitdem ich die Flagklassen entworfen habe.
    Ergo gilt auch das Argument von Shade, bzgl. if( win ). Ein offizielles und ernstgemeines Sorry an ihn und einen nicht ganz so ernstgemeinten Kniefall. 😉

    Da siehst du es - noch nicht einmal du selber weißt, was man mit deinen Flag-Klassen machen kann. Wie soll da noch ein anderer Programmierer, der nur deinen Code sieht, da durchblicken?

    *lach*, ich habe die Klasse jetzt seit locker einem Jahr nicht mehr angeguckt. Sie funktioniert einwandtfrei. Das Problem ist nicht, dass ich da nicht durchblicke, sondern dass ich derzeit in zwei ähnlichen Sprachwelten hänge.

    Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?

    Xin schrieb:

    Auch meine Klassen sind mit Doxygen dokumentiert. Aber nicht, weil sie nicht intuitiv wären, sondern weil es soviele sind, dass ich nicht immer alles im Kopf halten kann. Muss man irgendwo etwas ändern, wo man ein paar Jahre nicht mehr vorbeigeschaut hat, so ist die Dokumentation hilfreich.

    Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.

    CStoll schrieb:

    Zwei operator &-Funktionen stehen zur Auswahl. Eine Signatur passt perfekt, die andere passt überhaupt nicht.
    Und der Aufruf soll mehrdeutig sein.

    Nicht ganz - die Funktion Window hat keinen einzigen operator& - aber es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, die passen könnten.

    Das kann nicht die Erklärung sein, denn das würde die Verwendung von vererbten Funktionen jeglicher Art verhindern. Es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, von denen aber eine überhaupt nicht passt und eine genau passt.

    Keine der Funktionen passt genau - bei beiden müsste der erste Operand umgewandelt werden in eine Basisklasse.

    Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:

    ARM schrieb:

    Access to base class members must be unambigous. Access to a base class member is ambiguos if the expession used refers to more than one function, object, type, or enumerator. The check for ambiguity takes place before access control (§11). For example,

    class A {
    public:
      int a;
      int (*b)();
      int f();
      int f(int);
      int g();
    };
    
    class B {
      int a;
      int b();
    public:
      int f();
      int g;
      int h();
      int h(int);
    };
    
    class C : public A, public B {};
    
    void g(C* pc)
    {
      pc->a = 1;  // error: ambigous: A::a or B::a
      pc->b();    // error: ambigous: A::b or B::b
      pc->f();    // error: ambigous: A::f or B::f
      pc->f(1);   // error: ambigous: A::f or B::f
      pc->g();    // error: ambigous: A::g or B::g
      pc->g = 1;  // error: ambigous: A::g or B::g
      pc->h();    // ok
      pc->h(1);   // ok
    }
    

    If the name of an overloaded function is unambiguously found overloading resolution also takes place before access control.

    [...]

    Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.

    (das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)

    Oder auf deutsch: Zuerst wird überprüft, ob es einen eindeutigen Weg gibt, den Namen zuzuordnen, erst danach wird kontrolliert, ob er passt (betrachte den vierten Aufruf dort oben - es gibt nur einen f(int), aber er ist trotzdem mehrdeutig).

    PS: Ich hab' nochmal über die Typerweiterungen nachgedacht - und in C++ sind die wohl besser mit Konvertierungsoperatoren darstellbar:

    class WinFlag {...};
    class Window
    {
      WinFlag f;
    public:
      operator WinFlag&() {return f;}
      ...
    };
    


  • CStoll schrieb:

    Xin schrieb:

    Du wirst die Zwischenzeile danach bei mir zu schätzen wissen 😉

    OK, ich werde mich in Zukunft bemühen.

    Klappt doch super 🙂
    👍

    CStoll schrieb:

    Xin schrieb:

    CStoll schrieb:

    Xin schrieb:

    Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.

    Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.

    Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.

    Ich will es aber an dem Ort wissen, wo ich die Flags verwende - dem Code

    dlg = Dialog::Fullscreen;
    dlg = Dialog::Modal;
    

    sieht man nicht an, ob der Dialog hinterher noch im Vollbild-Modus ist oder nicht (und selbst mit expliziten Angaben WindowFlag::Fullscreen bzw. DialogFlag::Modal mußt du erstmal nachsehen, welchen Typ beides hat - ein Anwender könnte durchaus auf die Idee kommen, die DialogFlag-Klasse nur als Sammlung von zusätzlichen WindowFlag-Werten anzulegen).

    Das hatten wir doch schon durchgekaut: Flags setzt man nicht mit =, sondern mit |=.
    operator = wird protected, damit man die Defaultwerte setzen kann und diejenigen sicher sind, die damit nicht klarkommen.
    Zumal die Problematik sowieso erledigt ist, weil der Compiler den Operator mehrdeutig findet.

    CStoll schrieb:

    Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.

    Dann nenn die Klasse Flagable. 😉

    Aber auch hier gilt, es spielt eigentlich keine Rolle mehr, da der Compiler die Geschichte nicht akzeptiert. Ich kann noch so tolle Ideen haben, solange sie in C++ nicht kompilierbar sind, taugen sie für C++ nichts.

    Dass die Methode in C++ auch noch mehr Disziplin benötigt, als ich erwartete (genausoviel, als würde man ein Integer und Defines nehmen), macht die Sache nicht besser - von der Idee her aber auch nicht schlechter oder gefährlicher.

    CStoll schrieb:

    Xin schrieb:

    Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.

    Wenn du das aus dieser Sicht siehst, dann sollten die konkreten Flag-Werte aber keine Objekte der Klasse "Flags" sein - diese präsentieren nämlich ein einzelnes Flag.

    ...und ich dachte, ich wäre kleinlich.
    Also in Zukunft class WindowFlag mit den einzelnen Flags, das wird dann protected auf WindowFlags abgeleitet, welches dann public auf Window abgeleitet wird. Ergebnis: WindowFlag(ohne s) enthält die einzelnen Flaggen, WindowFlags verwaltet viele Flaggen und Window weiß von nichts. (Nein, ich habe es nicht ausprobiert, das kam nur grade dabei rum, dass Du die Flags und das einzelne Flag auch noch trennen möchtest. Ob und wenn ja, was für Merkwürdigkeiten dabei rumkommen, juckt mich in dem Thread weniger, weil es ja nicht kompiliert.)

    CStoll schrieb:

    Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?

    Das Design ist leicht zu durchschauen, da braucht man nichtmals guten Willen dazu.
    Wenn man natürlich operator & erst versteht, wenn man darauf aufmerksam gemacht wird, dass man das bei Integers genauso macht, dann frage ich mich, ob der ursprüngliche Wille nicht in die andere Richtung ging 😉

    CStoll schrieb:

    Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.

    Wer if( win.Flags ) benutzt wird sowieso gesteinigt, sofern das nicht explizit erlaubt und begründet ist. Sobald da eine Flage hinzugefügt wird, die unabhängig von den Flaggen ist, die damit abgefragt werden wollen, geht das ganze schief. if( win.Flags & KombinationAusGewünschtenFlaggen ) ist wohl Pflicht, selbst wenn das alle existierenden Flaggen sind und der Rest nicht verwendet wird und grundsätzlich auf 0 steht.

    CStoll schrieb:

    Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:

    ARM schrieb:

    Access to base class members must be unambigous.
    [...]

    Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.

    (das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)

    Würde ich gerne, insbesondere weil mich der Grund für diese Designentscheidung interessiert. Leider habe ich das ARM scheinbar nicht mehr, zumindest ist es verschwunden. :-\

    Du hast nicht zufällig die Begründung zum Quoten da?
    Alternativ nehme ich das ARM auch komplett 😉

    CStoll schrieb:

    PS: Ich hab' nochmal über die Typerweiterungen nachgedacht - und in C++ sind die wohl besser mit Konvertierungsoperatoren darstellbar:

    class WinFlag {...};
    class Window
    {
      WinFlag f;
    public:
      operator WinFlag&() {return f;}
      ...
    };
    

    Dem stimme ich zu.



  • Xin, hast du schon mal darüber nachgedacht Politiker zu werden?


Anmelden zum Antworten