模板功能专业化问题

时间:2009-08-20 08:20:58

标签: c++ enums

我正在使用模板来实现从int到enum的范围检查转换。它看起来像这样:

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"));

确保枚举总是在有效范围内。请注意,我并不总是控制这些枚举,所以这似乎是一个合理且易于配置的解决方案。

无论如何,这一切都很顺利(虽然我并不感觉这里给出的所有代码都是正确的,因为我现在只是从内存中回忆起来)

问题源于这样一个事实:只要将in分配给枚举,就可能希望在代码库中使用这个“enum_cast”构造。毕竟,这可以通过简单的搜索和替换操作来实施。当然,我不想为所有和每个枚举定义这些特化,但仅限于那些需要进行范围检查的人。我希望在需要时为枚举类型添加模板特化,并在没有定义特化时使用赋值运算符。

因此:

InternalEnum internal = enum_cast<InternalEnum>(internal_integer);

会有效地调用internal = internal_integer。我想我需要告诉编译器对所有没有专门化的枚举类型使用某个“默认”实现。

我的第一个赌注是给原始模板功能一个这样的实现:

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

不幸的是现在这个被调用,而不是更深入到项目目录树中的.cpp文件中的specialiazations。

有什么想法?

提前致谢 ·阿尔

3 个答案:

答案 0 :(得分:5)

显式特化必须在使用它们的任何地方都可见。由于它们是定义,因此不能在每个编译单元中重复它们。因此,在您定义枚举的头文件中,您要检查是否说

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

并在相应的.cpp中给出定义。

答案 1 :(得分: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专业化。对于您控制之外的任何枚举,边界检查只使用默认特征。

答案 2 :(得分: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;
}

Works On My Machine(TM)。它打印

default implementation
1
specialization
1