2008年12月7日 星期日

C++的列舉型別的type-safe問題

C++的enums(列舉型別)相當實用,特別是和#define, const int比起來
1. 型別檢查 (type-safe),這是#define, const做不到的。
2. 將相關的type放在別一個enums,不會像#define, const 定義的常數一樣,沒有group的概念。


enum Style
{
StyleA,
StyleB,
StyleC,
}

enum Area
{
Area1,
Area2,
Area3,
Area4,
}

// pass
Style s1 = StyleA;

// error, can't convert from int to enums 'Style'
s1 = 2;

// error, can't convert from enums 'Area' to 'Sytle'
s1 = Area3;

// pass, if you really need do it (it's non type-safe)
s1 = (Style)10;
s1 = (Sytle)Area4;

// ok, but it's non type-safe
int s2 = Area1;
s2 = Style1;


enums可以幫你在assignment operation時做型別檢查,避免你在寫程式時指定錯誤的type到enums裡,但是enums也不是所有的型別檢查都會做,考慮以下的清況:

Style s1 = Style1;

// pass and the complier will not say any errors
if (s1 == Area1)
{
// ...
}

為什麼會這樣呢,我想是C++因為沒有Implement operator==(Enum s1, Enum s2)的關係,且Enum可以implicit轉型為int,因此實際上呼叫的是operator==(int s1, int s2)的運算,這樣的結果會造成在enums的equal operation時缺少type-safe,而我認為type-safe對一個常常要mantain多個程式的programmer來說是非常重要的(其實即使只寫一個簡單的程式,我還是希望complier會幫我做type-safe XD),我之前就是碰到類似的問題,我拿別的enums來和我正在使用的enums來比較,並且complier也過了,因此我認為我的程式碼沒有問題了,如果有問題的話我的complier"應該"會告訴我才對,很不辛的,這個問題造成我的程式在客戶端才被發現錯誤(黑箱測試時並沒有測出這個bug orz),而且是在release數個月之後才由user發現的,這所花的成本我想遠比改寫程式為type-safe還花得高,因此後來我也慎重的告誡我們公司的程式設計師,這個type-safe的重要性。

那要怎麼解決這個問題呢,網路上有人寫了一個enums template class來包裝enums,他提供operator==(Enum s1, Enum s2)的運算,並且增加多個enums的bitwise運算(這個下一篇文章再提好了),強化我們的complier的錯誤檢查能力,並提升type-safe。

我使用的是這一個bitwise_enum class
google code的網址是:http://code.google.com/p/bitwise-enum/
目前的版本是1.2版 (http://bitwise-enum.googlecode.com/files/bitwise_enum-1.2.tgz)

#include "bitwise_enums.hpp"

// pass
bitwise_enums s1 = Style1;

// pass
s1 = Style2;

// pass
if (s1 == Style2)
{
// ...
}

// error, your complier will say it can't convert enums 'Area' to 'Style' for equal operation
if (s1 == Area1)
{
// ...
}


Notes:
1.
如果你打算使用bitwise_enums取代現有的寫法的話,因為bitwise_enum用了一些隱喻轉換的constrctor以及non-member operation function,可能會造成你現有的程式碼錯誤,如果要避開這個問題的話,可以將bitwise_enums用namespace包起來。


namesapce utils
{
#include "bitwise_enums.hpp"
}

utils::bitwise_enum s1 = Style1;


2. 如果你不擔心enums的type-safe問題的話,那你也就不用這麼麻煩了。 :)

References:
1. bitwise_enums
2. bitwise_enums ComplierErrors

沒有留言:

LinkWithin

Related Posts with Thumbnails