2017-06-18 72 views
0

我有一些像下面这样的任意枚举。为每个枚举器添加代码

enum MyEnumWith2Items { 
    Item1, 
    Item2 
}; 

enum MyEnumWith3Items { 
    Item1, 
    Item2, 
    Item3 
}; 

我想添加一些依赖于每个枚举的代码。例如,在每个项目对应的类中添加一个字段。

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 

这可能吗?
怎么样与enum class
如何使用static字段或方法或任何类型的代码?

类的定义可以采取任何形式,我的例子只是一个例子。
我可以使用任何版本的C++。

+0

[X-macro](https://en.wikipedia.org/wiki/X_Macro)会起作用。但它很大程度上依赖于预处理器,有些人认为它是一个丑陋的黑客。 – HolyBlackCat

回答

4

如果你有兴趣的myStruct静态成员,使用C++ 14 (所以静态模板成员均可),你可以定义myStruct如下

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 }; 

并给予下述普查员

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

可以写

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; 
} 

预C++ 14(以及在C++ 14本身),则可以使用在模板方法的静态变量获得相似的结果;以下是一个完整的示例

#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 
} 
+0

有趣,尽管有点丑陋的使用。 – Nelfeal

+0

@Nelxiost - 不好的部分是只允许定义静态变量;我不知道如何定义一个基于变量的对象集。 Passer的解决方案通过尝试解决这个问题,恕我直言,并不完美(需要连续值和终端'大小'),但很有趣。 – max66

+0

afaik你不需要'wrp'类型,你可以声明一个'template static int item',它仍然可以区分它们:https://ideone.com/l64qnY –

3

我的第一个想法是做这种事情,但有一个警告。

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 
} 

需要注意的是当然的enum小号必须为最终size诀窍是[0,n)的工作

0

这似乎有点多余,但它确实允许多态类型(如果需要)。我已经将不同的枚举类型包装为一组从基类型类继承的类。然后我使用了专业化的模板结构。我还添加了通过模板参数列表或通过公开分配类来设置值的功能。现在,这只是与实际列举的值一起工作;但是您可以轻松地添加到此以添加每个类型的字段。

#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; 
}