enum Style
{
StyleA = 0x01,
StyleB = 0x02,
StyleC = 0x04,
}
enums Area
{
Area1,
Area2,
Area3,
Area4,
}
// pass
Style s1 = StyleA;
// error, can't convert int to enums 'Style'
s1 = StyleA | StyleB;
很神奇的,為什麼StyleA | StyleB的結果無法放在s1裡呢,因為StyleA | StyleB的結果會是一個int而不是enum 'Style'。主要原因應該還是因為C++裡並沒有Enum operator |(Enum s1, Enum s2),而會implicit將enum轉成int,而改呼叫int operator (int s1, int s2),所以回傳值會是個int而不是enums囉。但是這不是我們預期的結果。
下面這樣的強制轉型可以解決上面的問題
// ok
Style s1 = static_cast<Style>(StyleA | Style B);
但是如果你不小心打錯了呢?
// pass, but what is 'StyleA' | 'Area4'??
Style s1 = static_cast<Style>(Style | Area4);
這樣的強制轉型方式缺乏type-safe。
另外如果你需要Enum Enum::operator |=(Enum s2) 這種運算的話,那現有的C++是不支援的喔
// error, no |=, &= operation in enums
s1 |= StyleC;
s1 &= StyleC;
所以很自然的你會改成下面這樣
// error, can't conver int to enums 'Style'
s1 = s1 | StyleC;
s1 = s1 & StyleC;
咦~ 又不對.. XD,因為跟之前的問題一樣,你需要做強制轉型將int轉成enum,所以在做bitwise operations會常常需要強制轉型。
function的參數也是一樣會遇到要強制轉型的問題
void foo(Style style)
{
// ...
}
void main()
{
/ error, can't conver int to enums 'Style'
foo(StyleA | Style B);
// pass, but it's non type-safe
foo(static_cast<Style>(StyleA | StyelB));
}
所以會看到有些lib的function的參數就不使用enum,改成unsigned int這種整數型態。
void foo(unsigned int style)
{
// ...
}
void main()
{
// pass, but it's non type-safe
foo(StyleA | Style B);
}
假設你改用bitwise_enum這個template class的話,除了上一篇講到的功能,當你在bitwise operations時依舊可以做到type-safe。
#include "bitwise_enums.hpp"
void foo(bitwise_enum<Style> style)
{
// ...
}
void main()
{
// pass
bitwise_enum<Style> s1 = StyleA | StyleB;
s1 |= StyleC;
foo(StyleA | StyleB);
// error, your complier will say it can't convert enums 'Area' to 'Style', :)
foo(StyleA | Area1);
}
不過用bitwise_enum有一些缺點,因為bitwise_enum有implict ctor自動將enum轉成bitwise_enum
bitwise_enum<Style> s1 = StyleA | StyleB;
if (s1.has_bits(StyleC)
{
// ...
}
Note:
1. 跟前一篇一樣,如果我們不去擔心type-safe的問題的話,那用強制轉型這樣其實也沒什麼問題的。
Reference:
1. bitwise_enums
2. bitwise_enums ComplierErrors
沒有留言:
張貼留言