2009-08-20 97 views
2

我正在使用模板來實現從int到枚舉的範圍檢查轉換。它看起來像這樣:模板功能專業化問題

template<typename E> 
E enum_cast(const int &source); 

模板函數或多或少放置在項目的root-directoy中。當定義一個已經預見到從一個配置文件這樣分配值的新的枚舉:

enum ConfigEnum { 
    ConfigEnumOption1 = 'A' 
    , ConfigEnumOption2 = 'B' 
    , ConfigEnumInvalid }; 

ConfigEnum option = XmlNode.iAttribute("option"); 

我定義爲在一個.cpp文件此枚舉中使用的模塊此特定枚舉類型一個模板特。

template<> 
ConfigEnum enum_cast(const int &source) { 
    switch(source) { 
    case ConfigEnumOption1 : return ConfigEnumOption1; 
    case ConfigEnumOption2 : return ConfigEnumOption2; 
    default return ConfigEnumInvalid; 
} 

現在一個int到枚舉的分配變爲:

ConfigEnum option = enum_cast<ConfigEnum>(XmlNode.iAttribute("option")); 

這可確保枚舉是在百達有效範圍。請注意,我並不總是控制這些枚舉,所以這似乎是一個合理且易於配置的解決方案。

不管怎麼說,這個工作都非常好(雖然我不是舒爾這裏給出所有的代碼是正確的,因爲我剛剛從存儲器中調用它現在)

問題來源於這樣的事實,這可能是desireable使用每當in被分配給一個枚舉時,這個「enum_cast」構造就會遍歷代碼庫。畢竟這可以通過簡單的搜索和替換操作來實施。當然,我不想爲所有和每個枚舉定義這些專門化,但僅限於那些需要進行範圍檢查的人員。我希望在需要時爲枚舉類型添加模板特化,並在未定義專門化時使用賦值運算符。

因此:

InternalEnum internal = enum_cast<InternalEnum>(internal_integer); 

將effecively調用內部= internal_integer。我想我需要告訴編譯器對所有沒有專門化的枚舉類型使用某個「默認」實現。

我的第一個賭注是給原始模板功能的實現是這樣的:

template<typename E> 
E enum_cast(const int &source) { 
    E copy = source; 
    return copy; 
}; 

不幸的是,現在這是所謂的百達而不是在.cpp,文件給出深入到項目目錄樹的specialiazations。

有什麼想法?

在此先感謝 阿恩

回答

4

明確的特化必須在使用它們的任何地方都可見。因爲它們是定義,所以在每個彙編單位都不能重複。所以在你定義一個枚舉的頭文件中,你想檢查你說的

#include "enum_cast.h" 
enum Foo { Foo_A, Foo_B, Foo_C }; 
template<> Foo enum_cast<Foo>(int source); 

並在相應的.cpp中給出了定義。

+0

感謝提示 - 像往常一樣,很容易,一旦你知道答案;-) – Arne 2009-08-20 09:25:15

0

#include <iostream> 

enum e1 { a, b, c, e1_invalid }; 
enum e2 { x, y, z, e2_invalid }; 

template<typename E> 
E enum_cast(int source) 
{ 
    std::cout << "default implementation\n"; 
    return static_cast<E>(source); 
} 

template<> 
e2 enum_cast<e2>(int source) 
{ 
    std::cout << "specialization\n"; 
    switch(source) { 
     case x: return x; 
     case y: return y; 
     case z: return z; 
    } 
    return e2_invalid; 
} 

int main(int /*argc*/, char* /*argv*/[]) 
{ 
    std::cout << static_cast<int>(enum_cast<e1>(1)) << '\n'; 
    std::cout << static_cast<int>(enum_cast<e2>(1)) << '\n'; 
    return 1; 
} 

作品在我的機器(TM)。它打印

default implementation 
1 
specialization 
1 
+0

這可能是因爲所有的特化都駐留在同一個文件中。在我的情況下,枚舉定義和特例化通常在單獨的文件中。 我想AProgrammer的意見將解決我的問題,雖然 – Arne 2009-08-20 09:24:37

+0

@Arne:我想是的。 – sbi 2009-08-20 10:55:09

1

你不能使用traits類來描述每個枚舉:

const int LARGE = 65536; 

template<typename> 
struct EnumTrait 
{ 
    enum {LOW = -LARGE}; 
    enum {HIGH = LARGE}; 
}; 

template<typename ENUM> 
static ENUM enum_cast (int i) 
{ 
    if (i < EnumTrait<ENUM>::LOW || i > EnumTrait<ENUM>::HIGH) 
     throw std::runtime_error ("Out of bounds"); 
    return static_cast<ENUM> (i); 
} 

enum Colour {RED = 0, GREEN, BLUE}; 

template<> 
struct EnumTrait<Colour> 
{ 
    enum {LOW = RED}; 
    enum {HIGH = BLUE}; 
}; 

enum Location {HERE = 0, THERE, NOWHERE}; 
// No EnumTraits class. 

int main (int argc, char* argv[]) 
{ 
    int i = 2; 

    Colour c = enum_cast<Colour> (i); 
    std::cout << "c=" << c << std::endl; 

    Location l = enum_cast<Location> (i); 
    std::cout << "l=" << l << std::endl; 

    return 0; 
} 

一般情況下,枚舉定義是伴隨着EnumTraits專業化。對於任何你不能控制的枚舉,邊界檢查只使用缺省特徵。

+0

我會考慮這種方法爲未來的項目,但現在我需要擊中截止日期..非常感謝! – Arne 2009-08-20 09:26:05