Flags kombinieren



  • Shade Of Mine schrieb:

    Deshalb verwende ich hier gerne Namespaces.

    dann kann man die flags doch gleich als static consts in die jeweilige klasse packen, oder?
    da wir hier ja im C++ forum sind und es somit auch um OOP geht: sind flags nicht irgendwie schlechter stil? entweder man definiert sie ausserhalb der klasse, was letztendlich den globalen namensraum zumüllt oder man packt sie in eine klasse bzw. einen namespace, was extrem unhandlich wird (A.SetFlags(KlasseA::FLAG1|KlasseA::FLAG2|KlasseA::FLAG3|KlasseA::FLAG4) )



  • maximAL schrieb:

    dann kann man die flags doch gleich als static consts in die jeweilige klasse packen, oder?

    In eine Klasse geht natürlich auch - auch wenn man sie dann missbraucht.
    Aber als static const? Nein, aber wirklich nicht. Wozu gibt es denn enum??

    da wir hier ja im C++ forum sind und es somit auch um OOP geht: sind flags nicht irgendwie schlechter stil?

    Wieso? Wie würdest du es 'Objekt Orientiert' lösen?

    entweder man definiert sie ausserhalb der klasse, was letztendlich den globalen namensraum zumüllt

    Und ich dachte immer für sowas gibt es namespaces...

    oder man packt sie in eine klasse bzw. einen namespace, was extrem unhandlich wird A.SetFlags(KlasseA::FLAG1,KlasseA::FLAG2,KlasseA::FLAG3,KlasseA::FLAG4) )

    using namespace KlasseA;
    A.SetFlags(FLAG1, FLAG2, FLAG3, FLAG4);
    (mal abgesehen davon, dass ich FLAG1 | FLAG2 | ... vorziehen würde)

    und dagegen die C Version:
    SetFlags(&A, KL_A_FLAG1,KL_A_FLAG2,KL_A_FLAG3,KL_A_FLAG4)

    mhm...
    ich kapier nicht worauf du hinaus willst...



  • Shade Of Mine schrieb:

    In eine Klasse geht natürlich auch - auch wenn man sie dann missbraucht.
    Aber als static const? Nein, aber wirklich nicht. Wozu gibt es denn enum??

    naja, was heisst missbraucht? immerhin sind die flags dann auch an die klasse gebunden, zu der sie gehören und fliegen nicht sonstwo rum.

    Wieso? Wie würdest du es 'Objekt Orientiert' lösen?

    ohne flags? 🤡
    nein, im ernst: das will ich ja grad selbst wissen.

    Und ich dachte immer für sowas gibt es namespaces...
    using namespace KlasseA;

    nunja, ist das ganze so nicht etwas überflüssig? sagen wir ich hab die klassen Klasse1, Klasse2, Klasse3. und dann steht da:
    using namespace Klasse1Flags;
    using namespace Klasse2Flags;
    using namespace Klasse3Flags;
    um die flags zu benutzen. da kann ich mir die namespaces doch auch gleich sparen, oder?

    (mal abgesehen davon, dass ich FLAG1 | FLAG2 | ... vorziehen würde)

    ups, wird gleich korrigiert...



  • maximAL schrieb:

    naja, was heisst missbraucht? immerhin sind die flags dann auch an die klasse gebunden, zu der sie gehören und fliegen nicht sonstwo rum.

    aso, ich dachte du willst eine Klasse als namespace missbrauchen. Dabei willst du ja nur sowas wie bei den fstream Klassen.

    Dann ists natürlich OK:

    Wieso? Wie würdest du es 'Objekt Orientiert' lösen?

    ohne flags? 🤡
    nein, im ernst: das will ich ja grad selbst wissen.

    Was stört dich an Flags?

    nunja, ist das ganze so nicht etwas überflüssig? sagen wir ich hab die klassen Klasse1, Klasse2, Klasse3. und dann steht da:
    using namespace Klasse1Flags;
    using namespace Klasse2Flags;
    using namespace Klasse3Flags;
    um die flags zu benutzen. da kann ich mir die namespaces doch auch gleich sparen, oder?

    Wieso?

    Du öffnest den namespace halt lokal...



  • Da hab ich doch gleich mal eine Frage:

    enum Foo {bla=1, blub=2};
    

    Sowohl 'bla', als auch 'blub' haben den Typ Foo, korrekt? Wenn ich jetzt 'bla | blub' schreibe werden sie implizit nach int gecastet und verknüpft, korrekt?

    Wie mach ich dann folgendes:

    void bar (Foo foo);
    
    bar (bla | blub);  // geht nicht: 'int' kann nicht nach 'Foo' konvertiert werden
    

    Das ist natürlich kacke.

    bar (static_cast<Foo>(bla | blub)); // Ne, nicht wirklich, oder?
    

    Was also machen? Eigene Klasse, mit überladenem 'operator |'? Möglich, aber aufwendig. Wie würde man sowas machen?



  • Helium schrieb:

    Was also machen? Eigene Klasse, mit überladenem 'operator |'? Möglich, aber aufwendig. Wie würde man sowas machen?

    unsigned nehmen



  • unsigned nehmen

    Erklär das mal bitte. 😕

    Wo unsigend nehmen? Als Argument an die Funktion? das ist doch auch Mist. Dann kann auch jeder schreiben:

    bar (42);
    

    Ne, ein wenig Typsicherheit hätte ich schon gerne.



  • unsigned für den Funktionsparameter. Foo würde ja heißen "einen der Werte in der Aufzählung Foo", was hier IMHO noch falscher wäre. Man kann damit zwar niemanden dazu zwingen, die richtigen Konstanten mit dem richtigen Operator zu kombinieren, aber dafür eine eigene Klasse zu schreiben finde ich auch übertrieben - dafür ist das Problem dann doch nicht groß genug 😉



  • Vielleicht sollte ich mal ein offizielles Proposal verfassen, das vorschlägt, dass der Rückgabetyp bitweiser Operatoren bei 'enum'-Instanzen auch ein Objekt vom selben Typ liefern.



  • Helium schrieb:

    unsigned nehmen

    Erklär das mal bitte. 😕

    Wo unsigend nehmen? Als Argument an die Funktion? das ist doch auch Mist. Dann kann auch jeder schreiben:

    bar (42);
    

    Ne, ein wenig Typsicherheit hätte ich schon gerne.

    dir sollte vollkommen egal sein, was jener oder anderer als Parameter übegibt, du überprüfst ja auf die gesetzte oder nicht gesetzte Bits.



  • OK, ich verwende zwei Bits, dezimal '1' und '2'. Jetzt übergibt jemand einfach '4'. Was jetzt? Ein Fehler, der erst zur Laufzeit aufgefangen werden kann. Bei einer typsicheren Lösung hätte ich gar nicht erst die Möglichkeit etwas falsch zu machen (ich meine unbeabsichtigt).



  • enum color { blue=1, red=2, yellow=4, green=8 };
    
    color c = 7; //sehr intuitiv...
    

    wie willst du das bewerkstelligen? entweder int und prüfen geht so

    int a = red | blue;
    if (a & red) ...
    if (a & green) ...
    etc.
    

    oder eben alle werte erlauben und implizit von int zu enumerator konvertieren.
    - ersteres finde ich besser, denn wenn ich nicht gerade flags verwende, erwarte ich, dass ein objekt typ color eine farbe von denen ist, die ich vorgebe.
    (außerdem: 7.2/5)

    was du noch tun könntest, wenn du einen kompromis suchst:

    Flag operator | (Flag a, Flag b) {
      return static_cast<Flag>(int(a)|b);
    }
    

    ein hässlicher workaround..



  • Shade Of Mine schrieb:

    Was stört dich an Flags?

    dass sie, wenn man sie auf herkömmliche art und weise verwendet (defines bzw. globale consts) keine bindung zur klasse/funktion haben. dann hat man da so eine funktion, die statt selbsterklärender parameter einfach irgendwelche flags will und muss sich erstmal durch den code wühlen, um herauszufinden, was man denn da nehmen könnte.
    die sache mit den namespaces ist imho auch nicht so toll. denn da besteht wieder die gefahr, dass ich 2 namespaces gleichzeitig verwende, in denen flags mit gleichem namen sind (sachen wie zb. TRANSPARENT etc. gibts wohl oft mehr als einmal).
    "sauber" scheint nur zu sein, wenn ich die flags direkt in die klasse packe, aber dann jedesmal KlasseA::FLAG zu schreiben geht einem auch ganz schnell auf den wecker...


Anmelden zum Antworten