2017-06-22 110 views
0

问题听起来令人痛苦熟悉。 假设你有枚举:在C++中自动将内在类型转换为enum

enum MyEnum {first, second, third}; 

现在我想一些INT转换为MyEnum。天真的做法

int i = 2; 
MyEnum e = (MyEnum)i; 

看起来好,但事实并非如此。首先,2将被转换为“第三”,而不是人们所期望的“第二”。其次,这种转换是愚蠢的,我想要一个聪明的。 动机如下:

void foo(MyEnum e) { ... } 
... 
foo(2); 

这FOO()应该总是收到“第二个” 2不管这是什么枚举的实际值。 有2个明显的解决方案:

  1. 写转换功能,并始终调用它
  2. 超载铸造操作

1解决方案显然是可怕的。不想写foo(convetIntToMyEnum(2));

我想写foo(2),编译器会自动调用我的转换函数。所以第二个解决方案就是我需要的。如果'int'是我自己的类,那么重载cast操作符是微不足道的。但'int'是内在类型。

我依稀记得有这种可能性,但找不到它。感谢我金发时刻的治疗。

+3

只要'enum MyEnum {first = 1,second,third};'。问题解决了。 – cdhowie

+0

不,我不想那样。特别是enum可以是{first = 0x1000,second = 0x2000 ...}。提示:枚举代表硬件的一些配置,所以我没有真正自由选择枚举项的值 – Noname

+0

那么为什么heck会映射到0x1000?这有点荒谬。如果你真的想追求这种混淆你自己的代码的奇怪愿望,可以考虑使用类而不是枚举。或查找表。或*字面上任何*除了隐式转换,将数字转换为其他数字。 – cdhowie

回答

3

对于枚举,您不能重载“铸造操作符”(通常这是一个“转换构造函数”或“用户定义的转换操作符”),因为它不是一个类,因此不能具有成员函数或构造函数。

你很可能想是这样的:

class my_enum 
{ 
public: 
    enum MyEnum {first=0x1000, second=0x2000, third=...}; 

private: 
    MyEnum m_value; 

public: 
    my_enum(int _value) { 
     switch (_value) { 
      case 1: m_value = first; break; 
      case 2: m_value = second; break; 
      case 3: m_value = third; break; 
      default: throw std::invalid_argument("invalid value"); 
     } 
    } 

    operator int() const { 
     switch (m_value) { 
      case first: return 1; 
      case second: return 2; 
      case third: return 3; 
      default:  return 0; 
     } 
    } 
}; 

void foo(my_enum e) 
{ 
    ... 
} 

您可以定义任何映射从int到你想要的,只要它是可逆的enum value。因为构造函数和转换运算符不是显式的,所以这将允许您想要的隐式转换。

+0

显然你是对的。我浏览了我的旧代码库,发现'operator <<'被重载(并且它也适用于本机类型),但是转换运算符看起来的确非常特殊。但是看起来很愚蠢,因为在C++中引入函数引用只是为了能够写foo(myObj)而不是foo(&myObj)。但是没有用户定义的从本地类型到枚举的转换。 – Noname

0

还有第三个明显的解决方案:不要使用整数作为您的函数的参数,而是直接使用您的枚举。只需将它作为一个枚举类就可以了!额外的好处:增加代码清晰度。这真的没有理由开始为糟糕的函数原型编写各种意想不到的转换。

如果这些函数是从外部API给你的,那么以适当的方式包装它们。如果你需要枚举成员的原始整数值,只需调用一个显式的转换函数。但是,通过访问硬件本身时的声音,这些呼叫站点也可以被打包,并且您可以在上面的所有层中自由选择正确的事物。

+0

我知道我可以明确地调用转换器。如果你仔细阅读我的文章,你会注意到我提到它作为选项1. 但我不希望显式调用转换器,我希望隐式地编译器调用转换器。 – Noname

+0

如果你仔细阅读我的答案,你会注意到我也告诉你不要调用foo(2),而是foo(MyEnum :: second)。这不是您考虑的选项。 – rubenvb

+0

好吧不能争辩,答案“不要做你需要的”是几乎任何问题的最终答案:)但我有理由将原生类型转换为枚举。 – Noname