std::variant mit enum class



  • Hallo

    kann ich einen std::variant<> definieren der einen beliebigen enum class enthält der auf int basiert

    also so was in der Art:

    enum class SomeEnum : int
    {
       Value1,
       Value2,
    };
    
    enum class OtherEnum : int
    {
       Apfel,
      Birne,
    };
    
    std::variant<double, int, enum class>
    


  • Ja.

    #include <variant>
    // ...
    std::variant<double, int, SomeEnum, OtherEnum> foo;
    


  • @Swordfish So wie die Frage formuliert ist denke ich er will einen variant<AnyIntBasedEnumThatSomeoneMayDefineSomehwere>. Und @booster nein, das geht nicht.



  • @hustbaer Ja, das habe ich schon verstanden. Aber sowas will man sowieso nicht. Denn wenn es egal ist welches enum es ist gibt es auch keinen wirklichen Grund für unterschiedliche Typen.



  • template<class Enum>
    using MyVariant = std::variant<int, double, Enum>;
    
    enum class SomeEnum : int
    {
    	Value1,
    	Value2,
    };
    
    enum class OtherEnum : int
    {
    	Apfel,
    	Birne,
    };
    int main()
    {
    	MyVariant<SomeEnum> a;
    	MyVariant<OtherEnum> b;
    }
    

    ?

    Oder

    template<class Enum>
    using MyVariant = std::enable_if_t<std::is_same_v<std::underlying_type_t<Enum>, int>, std::variant<int, double, Enum>>;
    

    Ist das sinnvoll? Ich kann mir keinen Fall ausdenken^^



  • @Swordfish
    Gründe könnte es schon geben sowas zu wollen. Vielleicht weil man neben dem Numerischen Wert auch prüfen können möchte welcher Typ es ist.

    Und ich finde es halt immer verwirrend wenn jemand eine Antwort auf eine "um-interpretierte" Frage stellt, ohne darauf hinzuweisen dass das es ihm bewusst ist dass das nicht die ursprüngliche Frage beantwortet.



  • @HarteWare Ich hatte die Frage eher so verstanden dass er eher eine Art any möchte. Also dass man den selben konkreten Variant Typ (kein Template) verwenden kann, um darin Werte verschiedener Enums zu speichern.



  • This post is deleted!


  • Wieder der klassische Fall wo der TE lieber beschreiben soll, was er tatsächlich erreichen will... Sonst können wir noch auf Ewigkeit rumraten.



  • Hallo zusammen

    Danke für eure Antworten.
    Ja sorry dass ich nicht die komplette Architektur erklärt habe.
    Es wird ein Container benötigt der aus einem externen System Variablen abholt und speichert. Die Datentypen beschränken sich eigentlich auf int und double. Damit in speziellen Fällen die integer nicht jedesmal bevor sie abgefragt werden in enums umgewandelt werden müssen war die Idee diese direkt als enum im Container abzulegen.

    Hustbear hat das gut erkannt:
    "Vielleicht weil man neben dem Numerischen Wert auch prüfen können möchte welcher Typ es ist."
    Danke.

    Template kommt auch nicht in Frage. Da wird mir dann wohl nichts anderes übrig bleiben als doch nur den int zu speichern.



  • Ich fürchte viel klarer ist es immer noch nicht geworden 🙂

    Da wird mir dann wohl nichts anderes übrig bleiben als doch nur den int zu speichern.

    Wer sagt denn das?
    Um welche Eigenschaften des Enum geht's dir denn im Speziellen? Also ... kannst du in Pseudo-Code einen konkreten Vorgang skizzieren wo du gerne hättest dass der Typ mitkommt?

    Wenn du z.B. nur auf Gleichheit prüfen können möchtest, dann kannst du zusätzlich zu dem int z.B. noch den std::type_index des Enum-Typs dazu speichern. Der lässt sich auch gut als Key für diverse assoziative Container verwenden (daher auch der Name).



  • ps: Dazu aber gleich noch eine Warnung: Die type_info Objekte für Typen die aus einer dynamisch geladenen Library (DLL/SO) kommen, verdampfen üblicherweise* automatisch mit der Library wenn diese entalden wird. Ich vermute stark dass dadurch auch üblicherweise alle type_index Objekte "kaputtgehen" die über type_infos aus der Library erstellt wurden. Und "kaputtgehen" kann dabei leicht "undefiniertes verhalten" heissen sobald man noch irgendwas mit denen macht (kopieren, vergleichen, zerstören -- irgendwas).

    *: Soweit ich weiss "kennt" der C++ Standard immer noch keine Libraries, speziell keine dynamisch geladenen Libraries. Von daher sagt der zu dem Thema auch nix, und man kann nur gucken was die üblichen Implementierungen so machen.



  • Hallo Hustbear.
    Danke für deine Erklärung.

    Ich versuche auch mal zu erklären was ich vorhabe.
    Von einem externen System hole ich Werte von Variablen ab. Diese werden als _variant_t zurückgeleifert. Nun möchte ich gleich an der Stelle in den konkretten Typen umwandeln. Also in int, double, float oder bool oder eben wenn in speziellen Fällen vom int in enum.

    Habe hier mal Code gepostet. Der Code ist nicht vollständig und nicht vollständig soll nur mal zeigen was ich vorhabe.

    https://gist.github.com/MattiasEppler/cffc17b93d3d6aae37ca660fcd03a839



  • Edit: Ich glaub mein Code ist Quark, weil ich im Prinzip einfach ein doppeltes Variant gebaut habe ... smh


    Ich habe noch einen Vorschlag: Erstell ein enum class für die Typen, und verwende das als Tag. Dann auf der Konvertierungsseite ein großes switch-Case, dass basierend auf dem tag enum Wert in den Typ konvertiert:

    enum class TypeTag {
        Int,
        Float,
        EnumFruit,
        EnumVegetable
    };
    
    struct tagged_value {
        std::variant<double, float, int, bool> value;
        TypeTag tag;
    };
    
    template<class T>
    T convert_value(const tagged_value& val) {
        switch (val.tag) {
        // ...
        case TypeTag::EnumFruit:
            return static_cast<EnumFruit>(std::get<int>(val.value));
        // ...
        }
    }
    

    Ich checks noch nicht so ganz, aber ich schmeiß einfach mal wilde Ideen in Raum, kann ja nicht viel schaden. Geht davon aus, dass Du den tagged_value schon aus _variant_t erstellt hast. Das "Umwandeln" von int in enum, also der static_cast, kannst Du vernachlässigen... (im Sinne von performance overhead), Wertebereich prüfen wäre sinnvoll. Das enum als String ausgeben lässt sich damit auch gut lösen, wenn man statisch ein passendes Array anlegt, oder eine Funktion schreibt, welche die entsprechenden const char* zurückgibt. Ich bin da noch recht simple-minded, also Deinen Code verstehe ich nur wenn ich ganz lange drauf schaue und nebenher die Suchmaschine meines Vertrauens offen hab^^

    P.S.: Meine "Lösung" würde perfekt zum Titel dieses Threads passen :o)



  • Danke für deine Antwort HarteWare

    @HarteWare sagte in std::variant mit enum class:

    Erstell ein enum class für die Typen, und verwende das als Tag

    Aber das möchte ich ja nun nicht. Mein variant soll alle typen von double, float, int, bool aufnehmen können ohne dass ich den variant ständig erweitern muss.

    Mein enum class leitet ja auch von int ab. Dann sollte der std::variant denn doch auch aufnehmen können ohne dass ich die Unterklassen in der Definition aufnehmen muss.

    Ich möchte auch kein switch case haben.


Log in to reply