Objective-CのEnum

標準C++03ではenumの構文が拡張され、標準C++11では更に、scoped enumerationがサポートされたそうだ。

C++11のEnum 参考:
http://d.hatena.ne.jp/spinor/20110918/1316321563

Cのenumとの主な違いは、

enum型の前方宣言が可能
名前空間を汚さずに、identifier::nameで参照する
・整数型との変換に明示的キャストが必要

// 前方参照
enum class Signal : unsigned;

struct Foo
{
    // 前方参照したから、変数宣言できる
    Signal s;
};

// 列挙定義
enum class Signal : unsigned
{
    RED = 1,
    BLUE,
    YELLOW
};

// RED, BLUE, YELLOWは列挙型Signalの名前空間内の定数なので、名前衝突しない
static const int RED = 1;

void some_function() {
    Foo f;

    // 列挙値の参照は、identifier::nameの形式で行う
    f.s = Signal::BLUE;
}


Objective-Cでは、NS_ENUMマクロを使う。

typedef NS_ENUM(NSInteger, Signal) {
    kSignalRed = 1,
    kSignalBlue,
    kSignalYellow
};

NS_ENUMマクロは、コンパイル環境に応じて、サポートされている形式のenumを定義するらしい。
要するに下位互換目的。

Xcode 5.1で試したところ、.mm ファイルでコンパイルした場合、scoped enumerationとしてコンパイルされた。.m ファイルでコンパイルした場合は、unscoped enumerationとしてコンパイルされた。どちらでも前方宣言は可能だった。

NS_ENUMマクロを使うからには、基本的には、列挙値をidentifier::name形式で参照すべきではないだろう。

もっとも、iOS, OS X環境以外でObjective-Cを使うことなんてほとんどないだろうし、通常、Xcode以外で開発することもそうないだろうから、NS_ENUMの恩恵というのは、ほとんど感じられる機会はないのではなかろうか。ぜいぜい、Cのenumを直接使うよりは、幾分マシか、といったところだろう。


ちなみに、定数名を k で始めるのは、ドイツ語 konstant から来ているそうな。

このkで始める命名習慣はObjective-Cでしか見たことがないので、CやC++のプロジェクトで使うべきではないだろう。下手をすると、あなたのXcode.appへのリンクがEmacsに置き換えられてしまうという嫌がらせを受けるかもしれない。