Grösse von enums



  • Hi leute

    geht sowas?

    enum foo
    {
       eins, zwei, drei
    };
    
    int main()
    {
         cout << sizeof(foo) / sizeof(int) << endl;   // dass jetzt 3 rauskommen würde
    }
    

    also sprich dass man ohne andere konstanten zu definieren, die länge des enums quasi rauskriegen kann?
    sizeof(enum) ist meines wissens == sizeof(int), und das beispiel oben klappt auch nicht, jedenfalls nicht so wie ichs gern hätte

    gibt es da sosnt eine möglichkeit?

    mfg mosho



  • Kommt da nicht 1 raus, da ein enum eine Aufzählung = Integer mit den Werten 1... ist?

    Edit: Ach jetzt verstehe ich Deine Frage erst bzw. ich verstehe sie nicht... was möchtest Du denn erreichen?

    Ein enum ist eine Variable (int), dessen Werte man einfach Symbole "Eins", "Zwei",... zuordnen kann und den Wertebereich einschränken kann.



  • Skym0sh0 schrieb:

    gibt es da sosnt eine möglichkeit?

    Nein



  • Ja, gibt es:

    enum Blup
    {
      B_INVALID = -1,
    
      B_mein_erstes,
      B_mein_zweites,
      B_mein_drittes,
    
      B_LAST
    };
    

    Wenn man sich das angewöhnt hat man mit dem _LAST-Eintrag immer die Anzahl, kann auch wunderbar drüber iterieren etc. Vorausgesetzt natürlich das mit Invalid ist der einzige zugewiesene Eintrag.



  • Skym0sh0 schrieb:

    ohne andere konstanten zu definieren

    Das geht nicht. Du musst da zu was Dynamischerem als enum greifen, bei dem du Laufzeitinformationen hast. std::map<const char*, int> beispielsweise.



  • ne bruachs ja nur zur kompilezeit

    geht drum ich möchte folgendes machen:

    string str[anzahl_der_dinger_im_enum];
    
    enum
    {
        eins,
        zwei,
        drei,
        ...
    };
    

    wenn ich jetzt noch die vier ins enum schriebe hätte ichg erne dass das array dann auch eins grösser wird...



  • Fellhuhn hat die Lösung doch schon gepostet.



  • aber sowas wie ich mir dachte (dieser sizeof kram) gibts nicht?



  • TyRoXx schrieb:

    Skym0sh0 schrieb:

    gibt es da sosnt eine möglichkeit?

    Nein



  • Aber wenn du einen _LAST-Wert mitaufnimmst,
    wird dieser ja sowieso angepasst ....



  • Zur Not lässt sich mit Makros eine Art Operator für die enum -Größe zusammenkloppen:

    #include <iostream>
    #include <cassert>
    using namespace std;
    
    #define ENUM_WITH_COUNT(name) struct name { enum Id {
    #define ENUM_END ,Count_Of_Ids }; };
    #define enum_size(name) name::Count_Of_Ids
    
    ENUM_WITH_COUNT(WindowType)
    	Button,
    	Window,
    	Checkbox
    ENUM_END
    
    int main()
    {
    	const size_t size = enum_size(WindowType);
    	assert(size == 3);
    	cout << size << endl;
    
    	//Positiver Nebeneffekt:
    	WindowType::Id id = WindowType::Button;
    
    	cin.get();
    }
    


  • -.- stimmt mit dem _LAST eitnrag gehts ganz gut
    kA wieso ich das die ganze zeit überlesen hab, sorry jungs

    die idee mit Macros find ich auch cool dazu auch ne frage

    wieso das struct
    das würde ja dann so aussehen

    struct ENUMNAME
    {
        enum Id
        {
             bla,
             bla2,
             counts_of_ids,
        };
    };
    

    eig bringt das sdoch nichts?
    ausser halt dass man immer nen anderen namen verwenden kann, aber wenn man das struct weglässt kann man doch auch andere namen verwenden...

    zu enums noch
    wenn ich die enum einträge selbst mit zahlen versehe, dann wird der nächste eintrag ohne explizite zahl um eins einfach erhört?!?



  • Skym0sh0 schrieb:

    die idee mit Macros find ich auch cool dazu auch ne frage

    Da würd ich vorsichtig sein. Nur um einen Last -Enumerator nicht hinzuschreiben das Ganze enum zu obfuscaten lohnt sich vielleicht nicht. Vor allem wenn andere den Code lesen (oder du nach einiger Zeit), kommen vielleicht Fragen und Unklarheiten auf.

    Skym0sh0 schrieb:

    wieso das struct

    Damit du qualifizierte Bezeichner hast: Statt

    Color a = Green;
    

    nimmst du

    Color::Type a = Color::Green;
    

    Damit verhinderst du auch Namenskonflikte.

    Skym0sh0 schrieb:

    zu enums noch
    wenn ich die enum einträge selbst mit zahlen versehe, dann wird der nächste eintrag ohne explizite zahl um eins einfach erhört?!?

    Ja. Jeder Enumerator hat den Wert des Vorgängers + 1, wenn nichts angegeben wird. Der erste Enumerator entspräche dann dem Wert 0.



  • Ich schlag einfach mal Metaprogrammierung vor, weil ich die
    Idee eigentlich gar nicht sooo schlecht finde:

    #include<iostream>
    
    template<typename T>
    int enumSize(const T& t){
            throw "size not available for enum";
    }
    
    enum foo
    {
       eins, zwei, drei
    };
    
    template<>
    int enumSize(const foo& t){
            return 3;
    }
    
    enum bar
    {
       rot, blau
    };
    
    template<>
    int enumSize(const bar& t){
            return 2;
    }
    
    int main() {
            std::cout << enumSize(eins) << std::endl;
            std::cout << enumSize(rot) << std::endl;
            return 0;
    }
    

    Ausgabe:

    3
    2
    

    Gruß,
    XSpille

    EDIT: Kann ich eigentlich irgendwie einen aussagekräftigen Compiler-Fehler erzwingen statt des Werfen einer Exception?



  • #error Ganz böser schlimmer Fehler!



  • XSpille schrieb:

    EDIT: Kann ich eigentlich irgendwie einen aussagekräftigen Compiler-Fehler erzwingen statt des Werfen einer Exception?

    Indem man die allgemeine Variante nur deklariert aber nicht definiert. Im Übrigen kann man sich aber den Zirkus mit den Templates sparen, da man das auch über ganz normale Funktionsüberladung hinbekommt. Trotzdem ist es aber unhandlich, weil man für jedes enum eine eigene Funktion schreiben muss.



  • XSpille schrieb:

    Ich schlag einfach mal Metaprogrammierung vor, weil ich die
    Idee eigentlich gar nicht sooo schlecht finde:

    #include<iostream>
    
    template<typename T>
    int enumSize(const T& t){
            throw "size not available for enum";
    }
    
    enum foo
    {
       eins, zwei, drei
    };
    
    template<>
    int enumSize(const foo& t){
            return 3;
    }
    
    enum bar
    {
       rot, blau
    };
    
    template<>
    int enumSize(const bar& t){
            return 2;
    }
    
    int main() {
            std::cout << enumSize(eins) << std::endl;
            std::cout << enumSize(rot) << std::endl;
            return 0;
    }
    

    Du mischst hier gerade zwei Konzepte: Funktionsüberladung und Type-Traits. Wenn schon würde ich wegen der Compilezeit-Auswertung zu Traits tendieren, aber das hat gegenüber eines Count -Enumerators nur Nachteile. Du brauchst zusätzlichen Code, verkomplizierst das Ganze für nichts und riskierst sehr schnell Inkonsistenzen. Von daher würde ich diesen Ansatz in der Praxis nicht verwenden.



  • Mit einem static_assert geht das. Entweder selber schreiben oder vom Compiler das nutzen (falls vorhanden).



  • RedPuma schrieb:

    #error Ganz böser schlimmer Fehler!

    Da Preprozessordirektiven vorm Compilieren ausgeführt werden,
    kriegt man den Fehler dann immer

    ipsec schrieb:

    Indem man die allgemeine Variante nur deklariert aber nicht definiert.

    hmm... Kein Kommentar... Manchmal steht man auf dem Schlauch 🙄



  • @Nexus:

    Wenn ich das richtig verstanden habe, meinst du das mit dem
    Type traits Ansatz so (auch wenn du ihn nicht verwenden würdest):

    #include<iostream>
    
    template<typename T>
    int enumSize();
    
    enum foo
    {
       eins, zwei, drei
    };
    
    template<>
    int enumSize<foo>(){
            return 3;
    }
    
    enum bar
    {
       rot, blau
    };
    
    template<>
    int enumSize<bar>(){
            return 2;
    }
    
    int main() {
            std::cout << enumSize<foo>() << std::endl;
            std::cout << enumSize<bar>() << std::endl;
            return 0;
    }
    

    Sehe ich das richtig?


Anmelden zum Antworten