2011-01-07

異種enumの比較を防ぐ

Visual C++ 2010はenum classがない(SP1でもC++0xの機能を増やす予定はないとか)。

でも、enum classがなくても型チェックはある程度できる。

enum WeaponType {
    WEAPON_TYPE_MOCHI,
    WEAPON_TYPE_SALMIAKKI,
};
enum TreatsType {
    TREATS_TYPE_MOCHI,
    TREATS_TYPE_SALMIAKKI,
};
// the trick is here
void operator ==(WeaponType, int);
void operator !=(WeaponType, int);
void operator ==(int, WeaponType);
void operator !=(int, WeaponType);
void operator ==(TreatsType, int);
void operator !=(TreatsType, int);
void operator ==(int, TreatsType);
void operator !=(int, TreatsType);
void test() {
    if (WEAPON_TYPE_MOCHI != WEAPON_TYPE_SALMIAKKI) { // ok
        eat();
    }
    if (WEAPON_TYPE_MOCHI == TREATS_TYPE_SALMIAKKI) { // error!
        scream();
    }
}

enum#defineconstの羅列より短いから使っているだけなので、自分は使わないだろう」と思っていたが、昨日別種のenumを比較するコードを書いてバグを出し、30分悩んだ。なので少なくとも型チェックのところは欲しいと思うようになった。

type-safe enumのようなクラスでラップするという方法は確実だが、文字数がとても多いのでそらで書き下せる自信がない。「enumのまま型チェックをする」方法を考えていたら上記の方法を思いついた。

つまり、「比較のoperatorを定義して、実装しない」という方法だ。

最初は operator ==(WeaponType, TreatsType); のように定義していたが、 enum の数を増やすと爆発することに気づいて int に変えた。 int でないほうがエラーは多少読みやすい。

返り値を void でなく bool で定義すると、リンク時のエラーになる。 void で定義するとコンパイル時にエラーが出てくれるのでそうした。