傳統 enum 基礎語法
enum Color { RED, GREEN, BLUE }; // 未指定值:從 0 開始遞增
enum Status { OK = 1, ERROR = -1, PENDING = 0 }; // 可指定任意整數值
Color c = RED;
if (c == GREEN) { /* ... */ }
// 列舉值可隱式轉為 int
int val = RED; // val = 0
關鍵特性
- 作用域:列舉項輸出到**外層作用域**(
RED 直接可用),易造成命名衝突。
- 隱式轉換:列舉值 ↔
int 雙向隱式轉換,型別安全性弱。
- 底層型別:實現定義(通常為
int),無法指定。
- 前向宣告不可行:需完整定義才能使用。
C++11 強型別列舉:enum class / enum struct
enum class Color : uint8_t { RED, GREEN, BLUE }; // 可指定底層型別
enum class Status : int { OK = 1, ERROR = -1 }; // 預設 int
Color c = Color::RED; // 必須帶作用域
// int val = c; // 錯誤:無隱式轉換
int val = static_cast<int>(c); // 顯式轉換
// if (c == 1) {} // 錯誤:不能與整數比較
if (c == Color::RED) {} // 正確
enum class 優勢
| 特性 | enum | enum class |
| 作用域 | 外層 | 強作用域 (Color::RED) |
| 隱式轉 int | ✅ | ❌ 需 static_cast |
| 指定底層型別 | ❌ | ✅ : uint8_t |
| 前向宣告 | ❌ | ✅ enum class Color : uint8_t; |
| 位元運算友好 | 需轉型 | 需轉型,但可重載運算子 |
實戰模式:位元遮罩
enum class Permission : uint32_t {
READ = 1 << 0,
WRITE = 1 << 1,
EXEC = 1 << 2,
ADMIN = READ | WRITE | EXEC
};
inline Permission operator|(Permission a, Permission b) {
return static_cast<Permission>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
}
inline Permission operator&(Permission a, Permission b) {
return static_cast<Permission>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
}
Permission p = Permission::READ | Permission::WRITE;
if (p & Permission::READ) { /* 有讀權限 */ }
C++17/20 新增:std::to_underlying、using enum
// C++23: 取得底層值(替代 static_cast)
#include <utility>
auto val = std::to_underlying(Color::RED); // 型別為 uint8_t
// C++20: 將列舉項引入當前作用域
void draw(Color c) {
using enum Color; // 此作用域內可直接用 RED, GREEN, BLUE
if (c == RED) { /* ... */ }
}
常見誤區與避坑
| 錯誤代碼 | 問題 | 修正 |
enum { A, B }; enum { A, C }; | 同作用域重複定義 A | 改用 enum class 或不同命名空間 |
switch(c) { case 1: } (c 是 enum class) | case 標籤需同型別 | case Color::RED: |
printf("%d", c); (enum class) | 無隱式轉換 | printf("%d", (int)c); |
| 列舉值超出底層型別範圍 | 編譯錯誤/截斷 | 指定足夠大的底層型別 : uint32_t |
現代 C++ 選型建議
- 預設用
enum class:型別安全、無命名污染、可指定底層型別、支援前向宣告。
- 需與 C API/舊代碼互操作:用傳統
enum 或 enum class + 顯式轉換層。
- 位元旗標:
enum class Flag : uint32_t + 重載 operator|/&/^/~。
- 避免「魔術數字」:所有離散狀態、模式、錯誤碼一律定義為列舉,編譯期檢查完整性。
總結
enum class 是現代 C++ 列舉的標準形態,解決了傳統 enum 的作用域污染、隱式轉換不安全、底層型別不可控三大痛點。配合 C++20 using enum 與 C++23 std::to_underlying,既保有型別安全,又兼顧使用便利性。新專案**無理由**不使用 enum class。