enum zu String konvertieren



  • Hallo,

    ich habe das Problem, ein Objekt, das eine enum-ID hat, in einen String zu konvertieren, hab im Netz einen Makro-Hack dazu gefunden, den ich allerdings etwas unschön finde, da er ein statisches Feld braucht:

    class KeyEvent
    {
    public:
        enum Key {
            KE_None,
            KE_Any,
            KE_Esc,
            KE_Enter,
            KE_Q,
            KE_W,
            KE_E,
            KE_R,
            KE_T,
            [...]
            KE_Reserved
        };
    
        KeyEvent(KeyEvent::Key id);
    
        [...]
    
        string toString() const;
    
    private:
        Key key_;
        static const char* keyString[];
    };
    
    #define STRINGIFY(name) # name
    
    KeyEvent::KeyEvent(KeyEvent::Key key)
        : key_(key)
    {
    }
    
    string KeyEvent::toString() const
    {
        return keyString[key_];
    }
    
    [...]
    
    const char* KeyEvent::keyString[] =
    {
        STRINGIFY(KeyEvent::KE_None),
        STRINGIFY(KeyEvent::KE_Any),
        STRINGIFY(KeyEvent::KE_Esc),
        [...]
    };
    

    Das Makro STRINGIFY setzt einfach die enum-ID ein. Falls es da andere Möglichkeiten gibt, wäre ich für Tipps dankbar 🙂



  • Nein es gibt leider keine andere Möglichkeit, außer sich selber einen Parser zu basteln. Was ich auch für die prinzipiell bessere Lösung erachte. Die Makro-Methode hat mehrere Schwachstellen. Die String-Umwandlung prüft nicht ob der Bezeichner stimmt. Die Assoziation mit dem zugehörigen Enum-Wert ist nicht unbedingt sicher gestellt. Du musst alle Werte von Hand eintragen, weil du nicht über die enum iterieren kannst.
    An der Stelle wäre vielleicht noch die Überlegung wert, das ganze über eine Map zu lösen.

    std::map<enum Key, std::string> my_keys;
    
    #define ADD_KEY(NAME)   {my_keys[NAME] = std::string(#NAME);}
    

    Damit hast du zwar immer noch das Problem nicht über die Liste iterieren zu können, aber die Bezeichner werden geprüft und die Assoziation stimmt.



  • #define ENUM_CASE(x)  case x: return (#x)
    const char* AsStr(Key key)
    {
    	switch(key)
    	{
    		ENUM_CASE(KE_None);
    		ENUM_CASE(KE_Any);
    		ENUM_CASE(KE_Esc);
    		ENUM_CASE(KE_Enter);
    	}
    	return "UNKNOWN";
    }
    

    Wirklich schön ist das aber auch nicht...



  • Das beste, was mir dazu einfällt, sind X-Makros:

    // keyevent_key.list
    
    KEYEVENT_KEY(KE_None)
    KEYEVENT_KEY(KE_Any)
    ...
    
    #undef KEYEVENT_KEY
    
    class KeyEvent
    {
    public:
        enum Key {
          #define KEYEVENT_KEY(x) x,
          #include "keyevent_key.list"
        };
    
        KeyEvent(KeyEvent::Key id);
    
        [...]
    
        string toString() const;
    
    private:
        Key key_;
        static char const *const keyString[];
    };
    
    char const *const KeyEvent::keyString[] =
    {
      #define KEYEVENT_KEY(x) "KeyEvent::" #x,
      #include "keyevent_key.list"
    };
    

    Auf die Art kannst du dir die doppelte Buchführung sparen. Darum, dir die Strings irgendwo aufzubewahren, wirst du jedenfalls nicht herum kommen.



  • Ich mache das immer so, dass ich die Deklaration dupliziere und dann "{" durch "{\"" , "," durch "\",\"" und "\"\n" durch "\n\"" ersetzen lasse.
    Hat allerdings den Nachteil, dass man das wiederholen muss, wenn man Elemente zum enum hinzufügt oder verändert.

    Edit: Die Forensoftware mag wohl keine Backslashes.



  • Hallo,

    danke für die Anregungen...

    hab irgendwie das Gefühl, dass irgendws an meinem Ansatz/Design falsch ist. Im Prinzip geht es (nur) um Debug-Ausgaben, wenn ich ein KeyEvent ausgeben lassen will...

    Handler::onKeyEvent(KeyEvent k)
    {
        std::cerr << "key: " << k.toString() << std::endl;
        [...]
    }
    


  • Debugausgaben? Visual Studio löst dir doch im Debugger die Bezeichnungen auf und der gdb kann das soviel ich weiß auch. In VS machst du einfach einen Breakpoint in die Methode, wählst mit Rechtsklick bei Treffer und schreibst hinter die Zeile noch deine Variable in geschweiften Klammern. Weitere Erläuterungen findest du direkt im Dialog. Beim gdb musst du mal schauen, dort heißt das vielleicht Trace-Point. Aber du wirst den Debugger wahrscheinlich eher über deine IDE steuern wollen.


Log in to reply