2009-08-20 117 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