Reputation: 13269
I have some arbitrary enumerations like the following.
enum MyEnumWith2Items {
Item1,
Item2
};
enum MyEnumWith3Items {
Item1,
Item2,
Item3
};
I would like to add some code dependant on each of the enumerators. For example, adding a field in a class corresponding to each item.
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
Is that even possible?
How about with enum class
?
How about with static
fields or methods or any kind of code?
The class definition can take any form, my example is just an example.
I can use any version of C++.
Upvotes: 0
Views: 74
Reputation: 7915
This may seem a little redundant but it does allow for polymorphic types if needed. I have wrapped the different enumeration types into a set of classes that are inherited from a base type class. Then I used a template structure with specialization. I also added in the ability to have the class set values either through the template parameter list or by publicly assigning them. Now this is just to work with the actual enumerated values; but you can easily add to this to add your fields for each type.
#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;
}
Upvotes: 0
Reputation: 66230
If you're interested in static members of myStruct
, using C++14 (so static template members are available), you can define myStruct
as follows
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 };
and given the following enumerators
enum MyEnumWith2Items { Item1, Item2 };
enum MyEnumWith3Items { Item3, Item4, Item5 };
you can write
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 (and in C++14 itself) you can obtain a similar result using a static variable in a template method; the following is a full example
#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
}
Upvotes: 4
Reputation: 21160
My first idea is to do this kind of thing, has a caveat though.
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
}
The caveat is of course that the enum
s must be [0, n) for the final size
trick to work
Upvotes: 3