Grösse von enums



  • 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?



  • Fast. Funktionen kannst du nicht zur Kompilierzeit ausführen, deshalb greift man zu Metafunktionen (Klassen, die zur Metaprogrammierung verwendet werden).

    enum A {...};
    enum B {...};
    
    template <typename Enum>
    struct EnumSize;
    
    template <>
    struct EnumSize<A>
    {
        static const size_t value = 4;
    };
    
    template <>
    struct EnumSize<B>
    {
        static const size_t value = 5;
    };
    


  • Nexus schrieb:

    Fast. Funktionen kannst du nicht zur Kompilierzeit ausführen, deshalb greift man zu Metafunktionen (Klassen, die zur Metaprogrammierung verwendet werden).

    enum A {...};
    enum B {...};
    
    template <typename Enum>
    struct EnumSize;
    
    template <>
    struct EnumSize<A>
    {
        static const size_t value = 4;
    };
    
    template <>
    struct EnumSize<B>
    {
        static const size_t value = 5;
    };
    

    MERCI!!!


Anmelden zum Antworten