2015-06-12 147 views
2

我有以下枚舉,並很可能在項目開發的過程中進行擴展:刪除列舉元素的重複

enum myEnum { 
    Element1, 
    Element2, 
    Element3 
    ... 
    ElementX 
    Last 
}; 

我有一個使用枚舉通過以下方式功能:

bool CheckEnumValidity(myEnum a) 
{ 
    bool valid = false; 
    switch (a) { 
    case Element1: 
    case Element2: 
    case Element3: 
    case ... 
    case ElementX: 
     valid true; 
     break; 
    case Last: 
     valid false; 
     break; 
    }; 
    return valid; 
} 

問題:

1)I重複Element1在,Element2等我的計劃中有兩個地方。如何以最安全的方式擺脫重複?

2)如果我有default行爲拋出異常(或因爲CheckEnumValidity()具有myEnum類型的參數上述switch語句返回false)?

注:

C++ 11是我的應用程序不可用。

+0

使用'enum class myEnum'或一個名稱空間。 –

+0

C++ 11不適用於我的應用程序 – Konstantin

+1

我給你留下了一個解決#2的問題,但是對於#1,試着看看這個(免責聲明:無恥的插件):https://github.com/aantron/better-enums。這給了你一個'is_valid'方法,消除了'Last'的需要,並且也給了你像'enum class'一樣的範圍和大小的枚舉,即使你沒有使用C++ 11。 http://aantron.github.io/better-enums/ApiReference.html#_is_valid_integral您基本上需要某種宏來避免重複,並且這會嘗試捕獲一些最有用的方法。 – antron

回答

2

假如你真的枚舉不包含任何明確的賦值,那麼你可以這樣寫:

if (a <= Last) { 
    return (a < Last); 
} else { 
    throw AnyExceptionYouWant(); 
} 
+0

dlask,謝謝你的回覆!你能澄清我的第二個問題嗎?如果我有明確的價值分配該怎麼辦?除了最後一個之外,是否有任何機制可以從'enum'獲取所有元素? – Konstantin

+0

@Konstantin該異常對於指示意外的值很有用。 – dlask

1

它可能會更容易,通過編碼準則,同儕壓力,政策執行(解僱誰做的任何程序設計師不與編碼指南)或其他方式履行,以保證調用代碼,使用您的enum只有永遠用品命名值。

換言之,不允許的積分值轉換爲枚舉類型。畢竟,做這樣的事情首先否定了使用枚舉類型的大部分原因。

如果,儘管有這個建議,你想測試,我會寫一個解析你的頭文件的小程序,找到所有的enum類型,並自動生成你的SomeFunction()。通過makefile,很容易確保程序在相關頭文件更改時運行,這意味着該函數將被更新,重新編譯並鏈接到程序中,以使檢查與類型定義保持一致。

至於你的檢查功能是否應該拋出一個異常,這歸結爲一個值的測試失敗的後果。如果你的程序真的不能繼續,那就拋出一個異常。如果錯誤是良性的,你的程序能以某種方式繼續,只需登錄一個錯誤信息(例如,爲了std::cerr),並繼續。

1

要回答你的第一個問題,在C++中沒有非常簡單的方法來做到這一點,但我會留下你的問題的評論指向一些方法。

關於第二個問題,我建議你使用一個default情況。這是爲什麼。第一個原因是較弱,但最後兩個更強。

  1. 有人可能會將整數顯式轉換爲枚舉值而不檢查其是否有效。這應該被禁止,但它仍然有時會發生,你應該在運行時捕獲此編程錯誤,如果它是在代碼審查錯過。
  2. 您可能會讀取struct或來自不可信外部來源的其他數據,其中struct包含枚舉字段,並忘記正確驗證它。不受信任的外部源甚至可以是使用程序的較舊版本保存的文件,其中枚舉有一組不同的有效值。
  3. 您可能有某個未初始化的枚舉。

即使是一些如此簡單:

enum A {X = 1, Y, Z}; 

int main() 
{ 
    A foo; 

    switch (foo) { 
     case X: return 0; 
     case Y: return 1; 
     case Z: return 2; 
    } 
} 

至於你應該在默認的情況下做什麼,這取決於你的項目和具體枚舉。例如,如果枚舉在進入大部分程序之前總是被驗證,從而防止了無效值,並且如果這被違反,那麼失敗是可以的,那麼在打印適當的錯誤消息之後,您應該拋出異常甚至調用exit - 這是在運行時捕獲的編程失敗。

如果這樣的失敗不是一個選項,那麼至少應該至少在調試版本中嘗試記錄它,以便可以檢測到問題。

如果無效值對特定枚舉有意義,那麼根據它爲什麼有意義,根據您認爲適合的枚舉來處理它。