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 eine std::map<whatever, char const *> nehmen, je nachdem wie die Werte der enum 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 sondern out 😉



  • @Swordfish sagte in wie gebraucht man eine enum class ?:

    Du willst nicht cout sondern out 😉

    Das muss eine visual studio extension sein, deshalb widerspreche ich mal.



  • @5cript

    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 ist

    assert(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 mit

    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];
            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.


Log in to reply