エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

列挙型をインクリメント

C++での話。
列挙型の値を、最初から最後まで順に使いたいとき。たとえばこんなとき。

enum Month { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Nov, Oct, Dec };
// JanからDecまで順に使いたい...

試しにfor文を使ってみる。

for(Month month = Jan; month <= Dec; ++month) // ... (1)
{
    // ...
}

すると、++演算子がないのでコンパイルエラーに。
++monthの代わりにmonth += 1とやってみても、またmonth = month + 1とやってみてもやっぱりだめ。ようやくmonth = static_cast(month + 1)とやってコンパイルが通り、期待通りに動いてくれた。

こんな列挙型の使い方が正しいかどうかはちょっと脇に置いておいてもらって。

演算子が未定義なら定義したらいいんだろうかと、++演算子を書いてみた。

Month& operator ++ (Month& month)
{
    month = static_cast<Month>(month + 1);
    return month;
}

動きました。最初の(1)の書き方で正しく動きました。

調子に乗ってテンプレート化。

template<typename T>
T& operator ++ (T& value) // ... (2)
{
    value = static_cast<T>(value + 1);
    return value;
}

動きました。こうなると。これ一つを定義しておくと、どんな列挙型でも、列挙型でなくても数値を加算できるクラスだったら、なんでもインクリメントできてしまう。便利なような、物騒なような。
仕事で使うのは、今回は保留しました。

ついでに。(2)は前置演算子なので、後置演算子も。

template<typename T>
T operator ++ (T& value, int)
{
    T prev = value;
    ++value;
    return prev;
}

追記:後置演算子の内容、DRYの原則を破ってしまっていました。内容を「++value」に書き直しました。