Tengo algunas enumeraciones arbitrarias como las siguientes.

enum MyEnumWith2Items {
    Item1,
    Item2
};

enum MyEnumWith3Items {
    Item1,
    Item2,
    Item3
};

Me gustaría agregar un código dependiente de cada uno de los enumeradores. Por ejemplo, agregar un campo en una clase correspondiente a cada elemento.

template<typename EnumType>
struct MyStruct {
    /* magic */
};

MyStruct<MyEnumWith2Items> a; // a has the fields i1 and i2, but not i3
MyStruct<MyEnumWith3Items> b; // b has i1, i2 and i3

¿Es eso posible?
¿Qué tal con enum class?
¿Qué tal con los campos o métodos static o cualquier tipo de código?

La definición de clase puede tomar cualquier forma, mi ejemplo es solo un ejemplo.
Puedo usar cualquier versión de C ++.

0
Nelfeal 18 jun. 2017 a las 20:18

3 respuestas

La mejor respuesta

Si está interesado en los miembros estáticos de myStruct, utilizando C ++ 14 (para que los miembros de la plantilla estática estén disponibles), puede definir myStruct de la siguiente manera

template <typename E>
struct myStruct
 {
   template <E I>
   struct wrp
    { int value; };

   template <E I>
   static wrp<I> item;
 };

template <typename E>
template <E I>
myStruct<E>::wrp<I> myStruct<E>::item { 0 };

Y dados los siguientes enumeradores

enum MyEnumWith2Items { Item1, Item2 };
enum MyEnumWith3Items { Item3, Item4, Item5 };

Puedes escribir

int main ()
 {    
   myStruct<MyEnumWith2Items>::item<Item1>.value = 1;
   myStruct<MyEnumWith2Items>::item<Item2>.value = 2;

   myStruct<MyEnumWith3Items>::item<Item3>.value = 3;
   myStruct<MyEnumWith3Items>::item<Item4>.value = 4;
   myStruct<MyEnumWith3Items>::item<Item5>.value = 5;
 }

Pre C ++ 14 (y en C ++ 14) puede obtener un resultado similar utilizando una variable estática en un método de plantilla; el siguiente es un ejemplo completo

#include <iostream>

enum MyEnumWith2Items { Item1, Item2 };
enum MyEnumWith3Items { Item3, Item4, Item5 };

template <typename E>
struct myStruct
 {
   template <E I>
   int & item ()
    { static int value = 0; return value; }
 };

int main ()
 {
   myStruct<MyEnumWith2Items>  e2;
   myStruct<MyEnumWith3Items>  e3;

   e2.item<Item1>() = 1;
   e2.item<Item2>() = 2;

   e3.item<Item3>() = 3;
   e3.item<Item4>() = 4;
   e3.item<Item5>() = 5;

   std::cout << "e2: " << e2.item<Item1>() << ", " << e2.item<Item2>() 
      << std::endl;                              // print e2: 1, 2
   std::cout << "e3: " << e3.item<Item3>() << ", " << e3.item<Item4>() 
      << ", " << e3.item<Item5>() << std::endl;  // print e3: 3, 4, 5
 }
4
max66 18 jun. 2017 a las 18:02

Mi primera idea es hacer este tipo de cosas, aunque tiene una advertencia.

enum class Enum1 {a, b, size};
enum class Enum2 {c, d, e, size};

template<typename E>
struct S
{
    char field[size_t(E::size)];  
};

int main()
{
    S<Enum1> s1;
    S<Enum2> s2;
    std::cout << sizeof(s1.field) << std::endl << sizeof(s2.field) << endl;
    // 2 and 3
}

La advertencia es, por supuesto, que los enum s deben ser [0, n) para que el truco final size funcione

3
Passer By 18 jun. 2017 a las 17:55

Esto puede parecer un poco redundante, pero permite tipos polimórficos si es necesario. He incluido los diferentes tipos de enumeración en un conjunto de clases que se heredan de una clase de tipo base. Luego utilicé una estructura de plantilla con especialización. También agregué la capacidad de hacer que la clase establezca valores a través de la lista de parámetros de la plantilla o asignándolos públicamente. Ahora esto es solo para trabajar con los valores enumerados reales; pero puede agregar fácilmente a esto para agregar sus campos para cada tipo.

#include <iostream>

class Root {
public:
    enum Type {
        TYPE_1 = 1,
        TYPE_2,
        TYPE_3
    };
protected:
    Type type_;

public:
    explicit Root(Type type) : type_(type) {}
    virtual ~Root() {}
    Type getType() const {
        return type_;

    }
};

class Derived1 : public Root {
public:
    enum TwoItems {
        ITEM_1 = 1,
        ITEM_2
    } item_;

    Derived1() : Root(TYPE_1) {}
    explicit Derived1(unsigned itemValue) : 
        Root(TYPE_1), item_(static_cast<Derived1::TwoItems>(itemValue) ) {}

};

class Derived2 : public Root {
public:
    enum ThreeItems {
        ITEM_3 = 3,
        ITEM_4,
        ITEM_5
    } item_;

    Derived2() : Root(TYPE_2) {}
    explicit Derived2(unsigned itemValue) :
        Root(TYPE_2), item_(static_cast<Derived2::ThreeItems>(itemValue)) {}
};

class Derived3  : public Root {
public:
    enum FourItems {
        ITEM_6 = 6,
        ITEM_7,
        ITEM_8,
        ITEM_9
    } item_;

    Derived3() : Root(TYPE_3) {}
    explicit Derived3(unsigned itemValue) :
        Root(TYPE_3), item_(static_cast<Derived3::FourItems>(itemValue)) {}

};

template<typename ClassType, unsigned itemValue = 0>
struct MyStruct {
    ClassType derived_;
};

template<unsigned itemValue>
struct MyStruct<Derived1, itemValue> {
    Derived1 derived_{ itemValue };
};

template<unsigned itemValue>
struct MyStruct<Derived2, itemValue> {  
    Derived2 derived_{ itemValue };
};

template<unsigned itemValue>
struct MyStruct<Derived3, itemValue> {  
    Derived3 derived_{ itemValue };
};

int main() {

    MyStruct<Derived1, 2> structA;
    MyStruct<Derived2, 4> structB;
    MyStruct<Derived3, 8> structC;

    std::cout << structA.derived_.item_ << std::endl;
    std::cout << structB.derived_.item_ << std::endl;
    std::cout << structC.derived_.item_ << std::endl;
    std::cout << std::endl;

    structA.derived_.item_ = static_cast<Derived1::TwoItems>(1);
    structB.derived_.item_ = static_cast<Derived2::ThreeItems>(5);
    structC.derived_.item_ = static_cast<Derived3::FourItems>(9);

    std::cout << structA.derived_.item_ << std::endl;
    std::cout << structB.derived_.item_ << std::endl;
    std::cout << structC.derived_.item_ << std::endl;
    std::cout << std::endl;


    // Also

    MyStruct<Derived1> structA2;
    MyStruct<Derived2> structB2;
    MyStruct<Derived3> structC2;

    structA2.derived_.item_ = static_cast<Derived1::TwoItems>(1);
    structB2.derived_.item_ = static_cast<Derived2::ThreeItems>(3);
    structC2.derived_.item_ = static_cast<Derived3::FourItems>(7);

    std::cout << structA2.derived_.item_ << std::endl;
    std::cout << structB2.derived_.item_ << std::endl;
    std::cout << structC2.derived_.item_ << std::endl;

    char c;
    std::cout << "\nPress any key to quit.\n";
    std::cin >> c;
    return 0;
}
0
Francis Cugler 19 jun. 2017 a las 01:10