Problem mit Bitoperatoren und enums


  • Administrator

    Nexus schrieb:

    Don Quijote schrieb:

    // Das geht schief
    Func(STYLE1|STYLE2);
    

    Was geht hier schief?

    Ganz einfach:
    Aus STYLE1 | STYLE2 kommt ein int heraus und nicht wie erwartet ein enum . Daher muss man casten.

    Grüssli



  • Dravere schrieb:

    Ganz einfach:
    Aus STYLE1 | STYLE2 kommt ein int heraus und nicht wie erwartet ein enum . Daher muss man casten.

    Ja, das habe ich auch erwähnt. Aber da pumuckl die Funktion mit einem int -Parameter deklariert hat...


  • Administrator

    Nexus schrieb:

    Dravere schrieb:

    Ganz einfach:
    Aus STYLE1 | STYLE2 kommt ein int heraus und nicht wie erwartet ein enum . Daher muss man casten.

    Ja, das habe ich auch erwähnt. Aber da pumuckl die Funktion mit einem int -Parameter deklariert hat...

    Achso, ich dachte du hättest von Don Quijote kopiert. Ganz übersehen, das asc das auch drin hatte. Ich denke mal er hat einfach ein Copy&Paste gemacht und vergessen, die Kommentare rauszunehmen. Programmiererfehler Nummer 1 😃

    Grüssli



  • Dravere schrieb:

    Ich denke mal er hat einfach ein Copy&Paste gemacht und vergessen, die Kommentare rauszunehmen. Programmiererfehler Nummer 1 😃

    Man man man... Copy/Paste der Segen und Fluch der Programmierer.



  • asc schrieb:

    Wenn du mit Flags arbeiten willst, solltest du
    a) Beim Enum die Wertigkeit angeben
    b) Einen Integralen Datentyp (int, long...) zur Übergabe verwenden

    // Enum-Definition
    enum Style {
      STYLE1 = 0x0001, // Bit 1 gesetzt
      STYLE2 = 0x0002, // Bit 2 gesetzt
      STYLE3 = 0x0004  // Bit 3 gesetzt
    };
    
    void Func(int newStyle);
    
    // Nun klappen auch die aufrufe:
    
    // So geht's
    Func(STYLE2);
    // Das geht schief
    Func(STYLE1|STYLE2);
    

    cu André

    Gut, das hat mir schonmal etwas weiter geholfen, aber was würde denn bei

    Func(STYLE1|STYLE2)
    

    an die Funktion übergeben werden? beide Bits oder nur 0x0002?


  • Administrator

    Don Quijote schrieb:

    Gut, das hat mir schonmal etwas weiter geholfen, aber was würde denn bei

    Func(STYLE1|STYLE2)
    

    an die Funktion übergeben werden? beide Bits oder nur 0x0002?

    Es käme ein 0x0003 an, oder in Bits ausgedrückt:

    STYLE1     := 0000 0001 = 0x01 = 1
         STYLE2     := 0000 0010 = 0x02 = 2
    STYLE1 | STYLE2 := 0000 0011 = 0x03 = 3
    

    Grüssli



  • Ok vielen Dank euch allen für die schnelle Hilfe 🙂



  • void Func( int newStyle )
    

    womit aber die schoene typsicherheit der enums dahin waere...
    Das kann nicht die beste Loesung sein



  • Geht aber nicht anders. Außer du definierst für jeden Müll einen Enumeintrag A_AND_B, B_AND_C, A_AND_B_AND_C etc.



  • Fellhuhn schrieb:

    Geht aber nicht anders.

    diesen Satz in Verbindung mit C++ zu lesen ist eine wahre Seltenheit...
    Fuer alles Erdenkliche existieren Patterns, also warum nicht auch fuer sowas Elementares?



  • Du kannst natürlich das Ergebnis wieder zum Enum-Typ casten, dann geht es. Aber da du dann einen "ungültigen" Wert bekommen kannst, bringt dir der ganze Enum-Klumbatsch eh nichts mehr.



  • #include <iostream>
    
    enum A
    {
        AFlag1 = 1,
        AFlag2 = 2,
        AFlag3 = 4,
        AFlag4 = 8,
    };
    
    enum B
    {
        BFlag1 = 1,
        BFlag2 = 2,
        BFlag3 = 4,
        BFlag4 = 8,
    };
    
    template<typename Enum>
    class Flags
    {
        typedef void** Zero;
        int i;
    public:
        typedef Enum enum_type;
        Flags( const Flags& f ) : i( f.i ) {}
        Flags( Enum f ) : i( f ) {}
        Flags( Zero = 0 ) : i( 0 ) {}
    
        Flags& operator=( const Flags& f ) { i = f.i; return *this; }
        Flags& operator&=( int mask ) { i &= mask; return *this; }
        Flags& operator&=( uint mask ) { i &= mask; return *this; }
        Flags& operator|=( Flags f ) { i |= f.i; return *this; }
        Flags& operator|=( Enum f ) { i |= f; return *this; }
        Flags& operator^=( Flags f ) { i ^= f.i; return *this; }
        Flags& operator^=( Enum f ) { i ^= f; return *this; }
    
        operator int() const { return i; }
    
        Flags operator|( Flags f ) const { Flags g; g.i = i | f.i; return g; }
        Flags operator|( Enum f ) const { Flags g; g.i = i | f; return g; }
        Flags operator^( Flags f ) const { Flags g; g.i = i ^ f.i; return g; }
        Flags operator^( Enum f ) const { Flags g; g.i = i ^ f; return g; }
        Flags operator&( int mask ) const { Flags g; g.i = i & mask; return g; }
        Flags operator&( uint mask ) const { Flags g; g.i = i & mask; return g; }
        Flags operator&( Enum f ) const { Flags g; g.i = i & f; return g; }
        Flags operator~() const { Flags g; g.i = ~i; return g; }
    
        bool operator!() const { return !i; }
    
        bool testFlag( Enum f ) const { return i & f; }
    };
    
    #define DECLARE_FLAGS(Fl) \
    inline Flags<Fl::enum_type> operator|( Fl::enum_type f1, Fl::enum_type f2 ) \
    { return Flags<Fl::enum_type>(f1) | f2; } \
    inline Flags<Fl::enum_type> operator|( Fl::enum_type f1, Flags<Fl::enum_type> f2 ) \
    { return f2 | f1; }
    
    typedef Flags<A> AFlags;
    typedef Flags<B> BFlags;
    
    DECLARE_FLAGS( AFlags );
    DECLARE_FLAGS( BFlags );
    
    int needA( AFlags test )
    {
        return test;
    }
    
    int needB( BFlags test )
    {
        return test;
    }
    
    int main()
    {
        std::cout << needA( AFlag1 | AFlag2 ) << std::endl; // geht
        std::cout << needB( BFlag1 | BFlag2 ) << std::endl; // geht
        std::cout << needA( AFlag1 | BFlag2 ) << std::endl; // geht nicht
        std::cout << needB( 3 ) << std::endl; // geht nicht
    }
    

    "geht nicht" gibts nicht 😉

    (leichte Abaenderung der Implementation der Qt-Bibliothek, also nicht mein Werk)


Anmelden zum Antworten