enum class und flags



  • hola leute

    hab mehrere enum classes die ich fuer kombinierte flags verwende. hab mir dafuer folgende hilfsklasse geschrieben:

    template<class T>
    class flags
    {
       public:
    	   typedef typename std::underlying_type<T>::type value_type;
    
    		flags(void) : m_value(0)
    		{
    
    		}
    
    		flags(T flag) : value(static_cast<value_type>(flag))
    		{
    
    		}
    
    		flags(T flag1, T flag2) : m_value(static_cast<value_type>(flag1) | static_cast<value_type>(flag2))
    		{
    
    		}
    
    		flags(const flags &fl) : m_value(fl.m_value)
    		{
    
    		}
    
    		flags& operator|(T flag)
    		{
    		   m_value |= static_cast<value_type>(flag);
    			return *this;
    		}
    
    		value_type value(void) const
    		{
    		   return m_value;
    		}
    
    		void clear(void)
    		{
    		   m_value = 0;
    		}
    
    	private:
    	   value_type m_value;
    };
    
    template<bool b>
    class check_if_type_is_enum;
    
    template<>
    class check_if_type_is_enum<true>
    {
    
    };
    
    template<class T>
    flags<T> operator|(T flag1, T flag2)
    {
       check_if_type_is_enum<std::is_enum<T>::value>(); // (1)
       return flags<T>(flag1, flag2);
    }
    

    damit kann ich nun folgendes machen:

    void print_flags(const flags<my_enum> &fl)
    {
       std::cout << fl.value();
    }
    
    enum class my_enum : int
    {
       flag1 = 1, flag2 = 2, flag3 = 4
    };
    
    int main(void)
    {
       print_flags(my_enum::flag1 | my_enum::flag2 | my_enum::flag3);
    }
    

    in zeile (1) erzeuge ich ein temporaeres objekt zur ueberpruefung ob T ein enum ist.
    gefaellt mir allerdings nicht so gut. wie kann ich das eleganter machen ?

    Meep Meep



  • static_assert

    Du willst wahrscheinlich aber eher SFINAE, schliesslich soll | nicht bei anderen Typen zu Compilerfehlern führen.



  • Aber mit dieser impliziten Konvertierung verlierst du doch wieder an Typsicherheit. Das gefällt mir nicht.



  • Nexus schrieb:

    static_assert

    Du willst wahrscheinlich aber eher SFINAE, schliesslich soll | nicht bei anderen Typen zu Compilerfehlern führen.

    ja bin draufgekommen das das eigendlich mist ist was ich da gemacht hab.
    wollte flags<T> meiner bibliothem in einem namespace hinzufuegen und dann kamen schon die probleme.
    hab ketz den globalen |operator direkt fuer die enums ueberladen, da es sonst mit anderen probleme gibr. wie kann ich das explizite ueberladen umgehen ?

    @Nexus
    die typsicherheit brauch ich dann in dem fall nicht mehr weil ich die kombinierten flags eh als in, DWORD oder sonst was brauche. mir gehts hauptsaechlich darum das ich die einzelnen flags eines enums bequem und halbwegs sicher kombinieren kann.

    Meep Meep



  • SFINAE erreichst du so:

    template<class T,
             typename = std::enable_if<std::is_enum<T>::value>::type >
    flags<T> operator|(T flag1, T flag2)
    {
       return flags<T>(flag1, flag2);
    }
    

    wie kann ich das explizite ueberladen umgehen ?

    Allerdings verstehe ich nicht, was gegen eine ganz gewöhnliche Enumeration spricht.

    mir gehts hauptsaechlich darum das ich die einzelnen flags eines enums bequem und halbwegs sicher kombinieren kann.

    Das funktioniert auch mit normalen enums. Das Ergebnis einer Kombinierung durch den |-Operator ist dann der underlying_type - das heißt, den Parameter musst du entsprechend abändern zu int o.ä.- aber dafür soviel Boilerplate zu schreiben ist doch Overkill.
    Arbeiten in deinen Projekten richtige Dödel mit, oder wieso willst du immer auf Nummer sicher gehen?


Anmelden zum Antworten