2017-06-22 116 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