Partage
  • Partager sur Facebook
  • Partager sur Twitter

Meilleur façon de wrapper un enum C en C++

    27 août 2021 à 12:51:03

    Salut,

    J'ai une lib écrite en C qui possède pas mal d'énums, et je veux la wrapper en C++

    voici un exemple simplifié de l'un de ces enum avec ses fonctions associées:

    enum TOTO
    {
        TOTO_NONE,
        TOTO_A,
        TOTO_B,
        TOTO_C,
        TOTO_NB,
    };
    
    const char* toto_get_name(enum TOTO toto);
    int toto_get_associated_value(enum TOTO toto);
    int toto_is_compatible(enum TOTO toto, int val);

    Et pour ce faire, je vois deux méthodes qui ont chacune leurs avantages et inconvénients, la première est juste de créer un enum class et d'encapsuler les fonctions C en C++, ce qui donne un truc du genre:

    enum class Toto
    {
        none = TOTO_NONE,
        a = TOTO_A,
        b = TOTO_B,
        c = TOTO_C,
    };
    
    std::string_view name(TOTO toto){
        return toto_get_name(static_cast<TOTO>(toto));
    }
    
    int associated_value(Toto toto){
        return toto_get_associated_name(static_cast<TOTO>(toto));
    }
    
    bool is_compatible(Toto toto, int val){
    return toto_get_associated_name(static_cast<TOTO>(toto), val); }

    La deuxième méthode est de créer une classe pour le type TOTO avec un enum classique interne et de transformer les fonctions libres en fonctions membres:

    class Toto
    {
    public:
        enum TotoValue
        {
            none = TOTO_NONE,
            a = TOTO_A,
            b = TOTO_B,
            c = TOTO_C,
        };
    
        constexpr Toto(Totovalue toto=none):
            m_value(toto)
        {}
    
    
        constexpr Toto(TOTO toto=none):
            m_value(static_cast<TotoValue>(toto))
        {}
    
        constexpr Toto& operator = (Toto toto){
            m_value = toto.m_value;
            return *this;
        }
    
        constexpr operator bool() const noexcept { return m_value != none;           }
        constexpr operator int()  const noexcept { return static_cast<int>(m_value); }
        constexpr bool operator == (TotoValue v) const noexcept { return m_value == v; }
        constexpr bool operator != (TotoValue v) const noexcept { return m_value != v; }
    
        std::string_view name() const noexcept {
            return toto_get_name(static_cast<TOTO>(m_value));
        }
    
        int associated_value() const noexcept {
            return toto_get_associated_value(static_cast<TOTO>(m_value));
        }
    
        bool is_compatible(int val){
            toto_get_associated_name(static_cast<TOTO>(m_value), val);
        }
    
    private:
        TotoValue m_value;
    };

    Je trouve la deuxième methode plus pratique à l'utilisation mais également plus lourde à écrire/maintenenir.

    Quel est selon-vous la meilleur façon de procéder ?

    -
    Edité par Orochi 27 août 2021 à 12:52:15

    • Partager sur Facebook
    • Partager sur Twitter
      27 août 2021 à 18:10:48

      Pourquoi veux tu "wrapper" un enum ? C'est quoi le but recherché, vu qu'un enum C et un enum C++, c'est la même chose ? Meilleure API ? Sécurisation de la mémoire ?

      La seule chose qui aurait pu être intéressant de wrapper, c'est le char* s'il y avait une gestion manuelle de la mémoire. Mais là, je sais pas trop.

      En gros, ma réponse serait : celle qui répond a ton besoin. Mais je ne suis pas sûr de voir le besoin.

      • Partager sur Facebook
      • Partager sur Twitter
        27 août 2021 à 18:51:46

        gbdivers a écrit:

        Pourquoi veux tu "wrapper" un enum ?

        La principale raison est que cela permet d'avoir des variable typées, il y a notamment du polymorphisme C-style de fait et donc certaines variables de type int contiennent en fait des types enum en fonction du contexte et j'aimerai faire du "vrai" polymorphisme par dessus pour éviter les codes su style:

        switch(type){
        case TYPE_TOTO: return toto_get_name(val);
        case TYPE_TUTU: return tutu_get_name(val);
        case TYPE_TATA: return tata_get_name(val);
        }

        -
        Edité par Orochi 27 août 2021 à 18:53:30

        • Partager sur Facebook
        • Partager sur Twitter
          27 août 2021 à 19:42:47

          Je ne suis toujours pas sur de comprendre. A partir du moment où tu n'utilises pas int comme paramètres, tu peux utiliser directement les enums.

          string get_name(TYPE_TOTO val);
          string get_name(TYPE_TUTU val);
          string get_name(TYPE_TATA val);
          
          TYPE_TUTU val;
          get_name(val); // pas de problème



          • Partager sur Facebook
          • Partager sur Twitter
            28 août 2021 à 11:10:13

            Bonjour,

            Tu sembles rechercher une résolution dynamique sur des types simple, c'est peut-être:

            #include <string_view>
            #include <variant>
            
            class TOTO_A {
            };
            class TOTO_B {
            };
            class TOTO_C {
            };
            using  UnTOTO = std::variant<TOTO_A,TOTO_B,TOTO_C>;  // un TOTO_X
            
            std::string_view  get_name( TOTO_A  val ) { return  "toto_a"; } // résolution statique
            std::string_view  get_name( TOTO_B  val ) { return  "toto_b"; }
            std::string_view  get_name( TOTO_C  val ) { return  "toto_c"; }
            
            std::string_view  get_name( UnTOTO  val ) { // résolution dynamique pour un TOTO_X quelconque
            	auto const  lbd_get_name = [](auto val){return get_name(val);};
            	return  std::visit( lbd_get_name, val );
            }
            
            int  main() {
            
            	TOTO_A  val_a;
            	get_name( val_a );     // résolution statique
            
            	UnTOTO  un_toto = TOTO_B{};
            	get_name( un_toto );   // résolution dynamique
            }
            
            • Partager sur Facebook
            • Partager sur Twitter

            En recherche d'emploi.

            Meilleur façon de wrapper un enum C en C++

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown