カンテラの光の下で

dNaga392's memorandom

【C++11】スコープ列挙型(Scoped enumerations)

TL;DR

enum classで定義した列挙型は、従来のenumに加えて、「整数型への暗黙の型変換を行わない」「列挙型のスコープを持つ」という機能を持つ。

enum class Color { Red, Green, Blue };

// 単にRedと指定するのではなく、どの列挙型に属するのかを指定する
Color c = Color::Red;

// 明示的な型変換は許可する
int color = static_cast<int>(Color::Red);
//int color = Color::Red; // コンパイルエラー : 暗黙の型変換はできない

Try it

cpp.sh で試してみた。intを基底にした場合でも暗黙の型変換は許されないようだ。

enum class Color : int { Red, Green, Blue };

int main()
{
    Color c = Color::Green;
    // int cc = Color::Blue;  // Error: cannot convert 'Color' to 'int' in initialization
    int cc = static_cast<std::underlying_type<Color>::type>(Color::Blue);
    return 0;
}

Diff

従来の手法との違いとしては、やはり次の2つが大きい。

  1. 「列挙型のスコープを持つ」
  2. 「整数型への暗黙の型変換を行わない」

「列挙型のスコープを持つ」に関してはメリットが大きい。

従来の列挙型で同様のスコープを実装したい場合、名前空間を使用して次のように実装していた。 これと比べるとずいぶんスマートになった。

namespace Color 
{
enum enumColor { Red, Green, Blue };
}  // namespace Color 

一方、「整数型への暗黙の型変換を行わない」については判断が分かれるかと思う。 というのは、整数型への暗黙の型変換を意図的に活用しているケースがあるからだ。

具体的には次のような場合がある。

namespace TableColumn
{
enum enumTableColumn { Id, Name, Address, numColumn };
}  // namespace TableColumn

この列挙型は次の2点で整数型への暗黙の型変換を意図的に活用される

  1. 各要素(Id, Name, Address)の並びに意味があり、列インデックス(int)として活用される。
  2. 末尾の要素(numColumn)が列挙子の数(int)として活用される。

実際にこういう運用は少なくないのでないだろうか。 このように順序に意味がある列挙型を、私は「順序付き列挙型(Enumerations with order)」と呼んでいる(正しい用語があれば教えてください)。

「順序付き列挙型」の場合、スコープ列挙型にしたところで キャストの手間がかかってしまうため、単純には導入できず検討が必要になるだろう。

Column

なお、末尾の要素で列挙子の数を定めることには是非があるようだ。

Ref