C++はenum class優先、通常enumの暗黙変換に注意|レビューで型安全性を高める設計原則
この記事のポイント
- enum class優先がレビュー標準である理由を整理
- 通常enumの暗黙変換・スコープ汚染問題を実務でどう検出するか解説
- 実務コード改善例とレビュー観点を提示
C++におけるenumの二系統
C++では以下2種類のenumが存在しています。
構文 | 特徴 |
---|---|
enum |
C由来、暗黙int変換、スコープ外部流出 |
enum class |
C++11以降、スコープ限定、暗黙変換禁止、型安全 |
歴史的背景
- Cとの互換維持のためenumは残存
- C++11以降、型安全文化徹底のためenum class導入
なぜenum class優先がレビュー標準なのか
① 暗黙int変換防止
enum Color { Red, Green, Blue };
int n = Red; // 暗黙int変換が許容
- 意味の異なるint型と混同されやすい
- 演算・比較の誤用バグが生まれやすい
② スコープ汚染防止
enum Status { OK, Error, Unknown };
Status s = OK; // グローバルスコープ直載せ
- 定数名衝突がプロジェクト規模拡大で多発
③ 型安全性向上
enum class Status { OK, Error, Unknown };
int n = Status::OK; // エラー: 暗黙変換禁止
- 意図しない混在を構文でブロック
- スコープ限定により衝突防止
レビューでの基本指針
判定対象 | レビュー指針 |
---|---|
enum | 原則禁止 |
enum class | 常用標準 |
暗黙変換 | 強制禁止 |
定数名衝突 | enum classで封じる |
良い実装例
良い例:enum class標準化
enum class Permission {
Read,
Write,
Execute
};
Permission p = Permission::Read;
if (p == Permission::Write) {
// 書き込み権限処理
}
良い設計理由
- 暗黙int変換なし
- スコープ汚染なし
- 定数名が限定範囲に閉じ込められる
レビュー観点
レビューアーは次を確認する。
- enum classを原則採用しているか
- 暗黙int変換を一切許容していないか
- スコープ汚染が発生していないか
- enum使用歴史コードは段階移行提案が進行しているか
- 既存enum互換部分は型明示キャストで明文化しているか
良くない実装例: ケース1
悪い例:古いenum使用
enum Permission { Read, Write, Execute };
Permission p = Read;
@Reviewer通常enumは使用禁止です。enum classに置き換えてください。@Reviewer定数名がスコープ汚染されています。
改善例
改善例:enum class化
enum class Permission { Read, Write, Execute };
Permission p = Permission::Read;
ケース2: 暗黙変換バグ温床
悪い例:int混入
enum Permission { Read, Write, Execute };
Permission p = Read;
int level = p; // 暗黙変換
@Reviewerenumからintへの暗黙変換は型安全性を崩壊させます。enum class適用で禁止しましょう。
改善例
改善例:暗黙変換排除
enum class Permission { Read, Write, Execute };
Permission p = Permission::Read;
// int型利用時は意図的キャストを明示
int level = static_cast<int>(p); // 必要な時だけ明示変換
ケース3: スコープ汚染の副作用
悪い例:別enumとの衝突
enum UserState { Active, Inactive };
enum TaskState { Active, Completed };
@Reviewer定数名Activeが衝突しています。enum class適用でスコープ分離してください。
改善例
改善例:enum classでスコープ隔離
enum class UserState { Active, Inactive };
enum class TaskState { Active, Completed };
ケース4: enum classでのint変換時に理由不明瞭
悪い例:キャスト理由不明
enum class Status { OK, NG };
int val = static_cast<int>(Status::OK);
@Reviewerキャスト理由(外部API互換など)をコメント付記してください。
改善例
改善例:理由付記
int val = static_cast<int>(Status::OK); // 外部プロトコル整数定義との互換用
int変換は最小限・理由明記が鉄則
ケース5: 古いAPI互換用enum混在
悪い例:古いAPI境界
enum OldFlag { FLAG_A = 1, FLAG_B = 2 };
void callLegacy(int flag);
callLegacy(FLAG_A);
@Reviewer内部コードはenum class移行し、API境界でint変換責務を分離してください。
改善例
改善例:内部型安全・境界型変換
enum class Flag { A = 1, B = 2 };
void callLegacy(int flag);
Flag f = Flag::A;
callLegacy(static_cast<int>(f));
enum class導入はレビュー技術向上の登竜門
課題領域 | enum classで防止できるリスク |
---|---|
型崩壊 | int混入事故 |
スコープ汚染 | 定数名衝突 |
レビューコスト | 型探索負荷 |
保守性 | 将来の値追加容易 |
観点チェックリスト
まとめ
レビューアーの役割は常にこう自問することです:
「enum classで安全性設計ができているか?」
- C++の型安全文化ではenum classはほぼ必須
- 通常enumは設計負債化しやすい
enum class採用=長期保守コスト削減設計です。
レビューで残存enumを必ず検出・移行提案できる力量が重要になります。