2017-06-18 57 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; 
}