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 jungsdie idee mit Macros find ich auch cool dazu auch ne frage
wieso das struct
das würde ja dann so aussehenstruct 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 Ganzeenumzu 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 2Gruß,
XSpilleEDIT: 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 immeripsec schrieb:
Indem man die allgemeine Variante nur deklariert aber nicht definiert.
hmm... Kein Kommentar... Manchmal steht man auf dem Schlauch

-
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!!!