[分享] C++11 : Strongly typed enumerations

看板C_and_CPP作者 (KITO)時間13年前 (2012/09/20 00:22), 編輯推噓7(705)
留言12則, 9人參與, 最新討論串1/2 (看更多)
好讀版 : http://kitoslab.blogspot.tw/2012/09/c11-strongly-typed-enumerations.html 因為我不太會上色所以這邊只有難讀版的XD.... - 回顧 enum 在 C++11 以前以下 enum 會污染整個 namespace 大致的意思是如果你宣告了一個 enum E, 他有 A, B, C 三個值 -------------------- Code ------------------ enum E { A, B, C, }; -------------------------------------------- 那麼在這個 namespace 底下你就不能先告任何以 A, B, C 為 ID 型別或變數 -------------------- Code ------------------ enum E { A, B, C, }; int A; /* Oop, compiler 會跟你抱怨 A 這個符號重複定義了!! */ -------------------------------------------- 而且很不近乎人情的你想要使用 E::A 的方式取值還會跟你抱怨 E 不是一個 namespace 或 class (在 VC++ 中有 extension 讓你可以這樣取) - C++11 前的折衷作法 這種情況事實上也不是不能解, 只要在 enum 外面包一層 namespace 即可, 但看起來會有點鳥就是了 -------------------- Code ------------------ namespace E { enum Type { A, B, C, }; } int A; /* A 這個 ID 可以用了! */ int var = E::B; /* 取用方式也以用 E:: 的方式取用 */ E::Type e = E::A; /* 最大缺點就是 Type name 會變成 E::Type */ -------------------------------------------- - enum 的型別問題 前一段包一層 namespace 的作法可以解決大部分的問題, 但是事實上 enum 還有一個問題就是, enum 常被拿來定義常數, 但是他實際的型別不明!! 在標準中也沒有規範 enum 要占多少大小 所以在大部分實作中, 大部分會以 int 來處理 在必要的時候他會長大成 64-bit 的 long long -------------------- Code ------------------ #include <stdio.h> enum E1 { A = 213, B, C, }; enum E2 { D = 21343245325435ll, E, F, }; int main(){ printf("%zd\n", sizeof(enum E1)); /* 印出 4 */ printf("%zd\n", sizeof(enum E2)); /* 印出 8 */ return 0; } /* 註: 環境是 Fedora 17 x86-64 編譯器為 g++ 4.6.3 以及 clang++ 3.2 */ -------------------------------------------- - enum 的型別問題在哪? -------------------- Code ------------------ enum E { A = 0x0ea92d6f << 4, B, C, }; int main(){ unsigned v = A; switch (v) { case A: /* gcc 4.6.3 可以 通過, clang 會跟你抱怨 - 359475472 沒辦法降轉到 unsigned! */ break; default: break; } return 0; } -------------------------------------------- -------------------- Code ------------------ enum E { A = 0x0ea92d6fu << 4, /*這邊加個 suffix u 就可解決 */ B, C, }; int main(){ unsigned v = A; switch (v) { case A: break; default: break; } return 0; } -------------------------------------------- 當然第一眼看到可能會覺得這是編譯器實作問題, 但是事實上最核心的問題是 enum 的型別是啥 個人認為這等於在整個型別檢查上開了個漏洞...雖然 C 的 Type system 本來就很薄弱 C++ 則是不幸的承受了 C 的一切 - Strongly typed enumerations C++11 中目前加入了 Strongly typed enumerations 以及一些語法上的改進 解決了上列所提到的問題點 * ENUM::VAL -------------------- Code ------------------ enum E { A = 0x0ea92d6f, B, C, }; int main(){ int v1 = E::A; /* Ohhh 現在這是合法的使用方式了 */ int v2 = A; /* 舊有取值方式向下相容 */ return v; } -------------------------------------------- * 型別問題 -------------------- Code ------------------ enum E : long long { /* 可以明確指定底層使用型別! */ A = 123, B, C, }; int main() { printf("%zd\n", sizeof(E)); /* 8 ! */ return 0; } -------------------------------------------- * Strong Type enum 除了可以拿來當常數宣告外, 在只拿來當列舉值時, 你可能就不會喜歡他能跟類 int 型別互轉不用錢的特性了 -------------------- Code ------------------ enum class E { /* 加個 class enum 換成 Strong Type! */ A = 123, B, C, }; int main() { int val = E::A; /* 跟你抱怨不能從 E 強轉成 int */ return 0; } -------------------------------------------- -------------------- Code ------------------ enum class E { /* 加個 class enum 換成 Strong Type! */ A = 123, B, C, }; int main() { int val = E::A; /* 跟你抱怨不能從 E 強轉成 int */ return 0; } -------------------------------------------- 接著他也可以跟前面指定形別的語法結合 -------------------- Code ------------------ enum class E : long long { /* 加個 class enum 換成 Strong Type! 並且指定為 long long */ A = 123, B, C, }; -------------------------------------------- 最後要注意一點的是雖然他加了個 class, 不過他依然只是 enum, 不能有 member data 及 member function 補充: g++ -std=c++0x 或 g++ -std=c++11 clang++ -std=c++0x 或 clang++ -std=c++11 可以切成 C++11 模式, 較舊clang/gcc版本需要使用前者 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.36.174.207 ※ 編輯: akasan 來自: 114.36.174.207 (09/20 00:22)

09/20 00:37, , 1F
09/20 00:37, 1F

09/20 00:48, , 2F
推 我是都把Enum包在Class裡面(非c++11)
09/20 00:48, 2F

09/20 00:52, , 3F
用namespace包, 閱讀會向 Color::Type color=Color::RED
09/20 00:52, 3F

09/20 05:56, , 4F
上次在改freerdp時才遇到這個問題,裡面用enum定義遠端桌面
09/20 05:56, 4F

09/20 05:58, , 5F
協定裡的標準header,我還在想為何不用define要用enum。
09/20 05:58, 5F

09/20 07:45, , 6F
Strong typed enum 指定型別的意義是什麼啊, 單純就可以
09/20 07:45, 6F

09/20 07:45, , 7F
列舉比較大的數字而已嗎...
09/20 07:45, 7F

09/20 08:54, , 8F
09/20 08:54, 8F

09/20 10:30, , 9F
推:希望可以多知道點c++11的內容.
09/20 10:30, 9F

09/20 12:58, , 10F
推薦這篇文章
09/20 12:58, 10F

09/20 16:13, , 11F
推,這篇解了我上篇的問題 :)
09/20 16:13, 11F

09/20 23:26, , 12F
Qt 的慣例都是把 enum 寫在 class 裡面
09/20 23:26, 12F
文章代碼(AID): #1GMV4xO2 (C_and_CPP)
文章代碼(AID): #1GMV4xO2 (C_and_CPP)