wie gebraucht man eine enum class ?
-
Hallo,
ich habe heute etwas von einer enum class "aufgeschnappt", und dachte das ich versuche ich mal:
#include <iostream> #include <vector> using namespace std; enum class E_COLORS : unsigned char { RED = 0, GREEN = 1, YELLOW = 2 }; ostream & operator<<( ostream & out, const E_COLORS & e) { out << e ; return out; } int main() { E_COLORS color = E_COLORS::YELLOW; cout << color << endl; return 0; }
Leider fehlt die Ausgabe - was will der compiler mir sagen? bzw. der testlauf? und wie bekäme man ein schönes ergebnis?
besten dank!
-
@patrickm123 sagte in wie gebraucht man eine enum class ?:
out << e ; // Zeile 13
Welche Funktion wird denn hier aufgeruft?
@patrickm123 sagte in wie gebraucht man eine enum class ?:
wie bekäme man ein schönes ergebnis?
Was wäre denn für Dich schön?
-
schön wäre zumindest ein zahl 0,1,2... noch schöner wäre es wohl besser als string "yellow"
-
@patrickm123 sagte in wie gebraucht man eine enum class ?:
Leider fehlt die Ausgabe - was will der compiler mir sagen? bzw. der testlauf?
Weißt Du denn schon warum das so ist? Wenn Du Dir meine erste Frage beantwortest würdest Du drauf kommen.
-
@Swordfish danke hab verstanden .... sich selbst unendlich oft aufrufen gibt probleme
so geht's z.b.
ostream & operator<<( ostream & out, const E_COLORS & e) { if (e == E_COLORS::YELLOW) { cout << "yellow" << endl; } else { out << "enum" ; } return out; }
-
@patrickm123 sagte in wie gebraucht man eine enum class ?:
sich selbst unendlich oft aufrufen gibt probleme
Bingo. Wenn Du den Zahlenwert willst gibt es
static_cast<>
und std::underlying_type. Für einen korrespondierenden String würde ich einen Lookup-Table oder einestd::map<whatever, char const *>
nehmen, je nachdem wie die Werte derenum class
verteilt sind.#include <type_traits> enum class E_COLORS : unsigned // char unsigned ist nicht so prickelnd für operator<<() 1) { RED = 0, // waere auch GREEN = 1, // die automatische YELLOW = 2 // Reihenfolge }; std::ostream& operator<<(std::ostream &out, E_COLORS const &color) { return out << static_cast< std::underlying_type_t< // so kann sich der underlying type aendern ohne dass man operator<<() aendern muss std::decay_t< // ref und const loswerden decltype(color) // typ von color > > >(color); }
Die Zeilenumbrüche sind nur wegen der Kommentare im Code.
Bzw für Strings:
#include <cstddef> #include <cassert> #include <type_traits> #include <iostream> enum class E_COLORS : unsigned { RED, GREEN, YELLOW }; char const *color_names[] { "red", "green", "yellow" }; template<typename T, std::size_t N> constexpr auto sizeof_array(T(&)[N]) { return N; } std::ostream& operator<<(std::ostream &out, E_COLORS const &color) { std::size_t index { static_cast<std::underlying_type_t<std::decay_t<decltype(color)>>>(color) }; assert(index < sizeof_array(color_names)); return out << color_names[index]; } int main() { std::cout << E_COLORS::GREEN << '\n'; }
oder
#include <type_traits> #include <stdexcept> #include <map> #include <iostream> enum class E_COLORS : unsigned { RED = 0, GREEN = 42, YELLOW = 84 }; std::map<std::underlying_type_t<E_COLORS>, char const *> const color_names { { static_cast<std::underlying_type_t<E_COLORS>>(E_COLORS::RED), "red" }, { static_cast<std::underlying_type_t<E_COLORS>>(E_COLORS::GREEN), "green" }, { static_cast<std::underlying_type_t<E_COLORS>>(E_COLORS::YELLOW), "yellow" } }; std::ostream& operator<<(std::ostream &out, E_COLORS const &color) { auto key { static_cast<std::underlying_type_t<std::decay_t<decltype(color)>>>(color) }; auto it { color_names.find(key) }; if (it == color_names.end()) throw std::invalid_argument { "You used a cast where you should have not." }; return out << it->second; } int main() { std::cout << E_COLORS::GREEN << '\n'; std::cout << static_cast<E_COLORS>(12) << '\n'; }
1) [ostream.inserters.character]
PS:
@patrickm123 sagte in wie gebraucht man eine enum class ?:
cout << "yellow" << endl;
Du willst nicht
cout
sondernout
-
@Swordfish sagte in wie gebraucht man eine enum class ?:
Du willst nicht
cout
sondernout
Das muss eine visual studio extension sein, deshalb widerspreche ich mal.
-
Schau es dir nochmals an.
-
@manni66
jupp, hast recht, hab mich verguckt.
-
@Swordfish Also ein Stream-Insertion-Operator sollte mMn. nie crashen, selbst wenn er "ungültigen" Input bekommt.
-
@hustbaer Ne, sollte er nicht. Höchstens
failbit
setzen.
-
@Swordfish
Na dann istassert(index < sizeof_array(color_names));
return out << color_names[index];
vielleicht nicht optimal
-
@hustbaer Ich habe mich schon gefragt was Du meinst. Ob jetzt aber
std::ostream& operator<<(std::ostream &out, E_COLORS const &color) { std::size_t index { static_cast<std::underlying_type_t<std::decay_t<decltype(color)>>>(color) }; if (index < sizeof_array(color_names)) return out << color_names[index]; return out << "undefined"; }
besser ist?
-
@Swordfish
Wie wäre es mitstd::ostream& operator<<(std::ostream &out, E_COLORS const &color) { std::size_t index { static_cast<std::underlying_type_t<std::decay_t<decltype(color)>>>(color) }; if (index < sizeof_array(color_names)) return out << color_names[index]; out.setstate(std::ostream::failbit); return out; }
-
@Schlangenmensch Auch schön ¯\_(ツ)_/¯
-
std::ostream& operator<<(std::ostream &out, E_COLORS const &color) { std::size_t index { static_cast<std::underlying_type_t<std::decay_t<decltype(color)>>>(color) }; if (index < sizeof_array(color_names)) return out << color_names[index]; return out << "#" << index; }
-
@hustbaer Doppelplusgut.