web-dev-qa-db-fra.com

Est-il possible de définir manuellement une conversion pour une classe enum?

Normalement, vous pouvez définir un transtypage pour une classe en utilisant la syntaxe suivante:

class Test {
public:
  explicit operator bool() { return false; }
};

Existe-t-il un moyen de faire cela ou quelque chose de similaire pour un enum class?

44
OmnipotentEntity

Non ce n'est pas.

En fait, un enum class n'est pas du tout une classe. Le mot clé class n'est utilisé que parce que le changement soudain de enum non délimité en enum de portée signifierait retravailler tous les codes énumérés. Le comité a donc décidé que pour faire la distinction entre les énumérations de style nouveau et ancien, les nouvelles seraient étiquetées avec class, car il s'agit déjà d'un mot clé, donc aucun enum n'aurait pu être nommé class en C++. Ils auraient pu en choisir un autre, cela n'aurait pas eu beaucoup plus de sens de toute façon.

Cependant, malgré le mot clé class, ce sont toujours des énumérations régulières dans la mesure où seuls les énumérateurs (et potentiellement les valeurs qui leur sont attribuées) sont autorisés entre crochets.

23
Matthieu M.

Non, mais vous pouvez faire en sorte qu'un type de classe normal agisse comme une classe enum, en utilisant les membres et les constructeurs constexpr. Et puis vous pouvez ajouter toutes les fonctions membres supplémentaires que vous souhaitez.


Preuve qu'il peut fonctionner même avec switch:

#include <iostream>

struct FakeEnum
{
    int x;

    constexpr FakeEnum(int y = 0) : x(y) {}

    constexpr operator int() const { return x; }

    static const FakeEnum A, B, Z;
};

constexpr const FakeEnum FakeEnum::A{1}, FakeEnum::B{2}, FakeEnum::Z{26};

std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
    int val;
    st >> val;
    fe = FakeEnum{val};
    return st;
}

int main()
{
    std::cout << "Hello, world!\n";
    FakeEnum fe;
    std::cin >> fe;

    switch (fe)
    {
        case FakeEnum::A:
        std::cout << "A\n";
        break;
        case FakeEnum::B:
        std::cout << "B\n";
        break;
        case FakeEnum::Z:
        std::cout << "Z\n";
        break;
    }
}

Preuve que travailler avec switch ne nécessite pas d'interconversion implicite avec int:

#include <iostream>

/* pseudo-enum compatible with switch and not implicitly convertible to integral type */
struct FakeEnum
{
    enum class Values { A = 1, B = 2, Z = 26 };
    Values x;

    explicit constexpr FakeEnum(int y = 0) : FakeEnum{static_cast<Values>(y)} {}
    constexpr FakeEnum(Values y) : x(y) {}

    constexpr operator Values() const { return x; }
    explicit constexpr operator bool() const { return x == Values::Z; }

    static const FakeEnum A, B, Z;
};

constexpr const FakeEnum FakeEnum::A{Values::A}, FakeEnum::B{Values::B}, FakeEnum::Z{Values::Z};

std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
    int val;
    st >> val;
    fe = FakeEnum(val);
    return st;
}

int main()
{
    std::cout << "Hello, world!\n";
    FakeEnum fe;
    std::cin >> fe;

    switch (fe)
    {
        case FakeEnum::A:
        std::cout << "A\n";
        break;
        case FakeEnum::B:
        std::cout << "B\n";
        break;
        case FakeEnum::Z:
        std::cout << "Z\n";
        break;
    }
    // THIS ERRORS: int z = fe;
}
16
Ben Voigt

Vous ne pouvez pas définir d'opérateurs de cast non membres en C++. Et vous ne pouvez certainement pas définir les fonctions membres pour les énumérations. Je vous suggère donc de faire des fonctions gratuites pour convertir votre énumération en d'autres types, de la même manière que vous implémenteriez des opérateurs de transtypage.

par exemple.

bool TestToBool(enum_e val)
{
    return false;
}

const char *TestToString(enum_e val)
{
    return "false";
}

Il y a une belle façon d'associer ces énumérations aux bools, vous devez le diviser en deux fichiers .h et .cpp. Le voici si cela aide:

enum.h

///////////////////////////////
// enum.h
#ifdef CPP_FILE
#define ENUMBOOL_ENTRY(A, B)            { (enum_e) A, (bool) B },
struct EnumBool
{
    enum_e  enumVal;
    bool    boolVal;
};
#else
#define ENUMBOOL_ENTRY(A, B)            A,
#endif


#ifdef CPP_FILE
static EnumBool enumBoolTable[] = {
#else
enum enum_e
{
#endif
ENUMBOOL_ENTRY(ItemA, true),
ENUMBOOL_ENTRY(ItemB, false),
...
};

bool EnumToBool(enum_e val);

enum.cpp

///////////////////////////////
// enum.cpp
#define CPP_FILE
#include "enum.h"

bool EnumToBool(enum_e val)
    //implement

Je ne l'ai pas compilé alors prenez-le facilement s'il y a des erreurs :).

4
imreal