我正在使用模板来实现从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。
有什么想法?
提前致谢 ·阿尔
答案 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