constexpr 登場

C++0x の機能の一つである constexpr が gcc 4.6 に実装されたようです.

constexpr が導入される事で,switch 文の case の箇所に関数が使えるようになる可能性が生まれます.自分が constexpr が欲しいなぁと感じた場面の一つが,複数の値を一つの変数に纏める関数 combine とメタ関数 combineN_ - Life like a clown のようにバイナリフォーマットを解析する際に,ヘッダのマジックナンバーのような値によって処理を分岐する必要のある場面でした.

template <class T1, class T2>
constexpr std::size_t combine(const T1& x1, const T2& x2) {
    return ((static_cast<std::size_t>(x1) & clx::mpl::lower_mask<sizeof(T1) * CHAR_BIT>::value) << (sizeof(T2) * CHAR_BIT)) |
        (static_cast<std::size_t>(x2) & clx::mpl::lower_mask<sizeof(T2) * CHAR_BIT>::value);
}

template <class T1, class T2, class T3>
constexpr std::size_t combine(const T1& x1, const T2& x2, const T3& x3) {
    return (combine(x1, x2) << (sizeof(T3) * CHAR_BIT)) |
        (static_cast<std::size_t>(x3) & mpl::lower_mask<sizeof(T3) * CHAR_BIT>::value);
}

template <class T1, class T2, class T3, class T4>
constexpr std::size_t combine(const T1& x1, const T2& x2, const T3& x3, const T4& x4) {
    return (combine(x1, x2, x3) << (sizeof(T4) * CHAR_BIT)) |
        (static_cast<std::size_t>(x4) & mpl::lower_mask<sizeof(T4) * CHAR_BIT>::value);
}

まだ実際にコンパイルしていないので動くかどうか分からないですが,上記のように記述する事によって以下のコードをコンパイルする事ができるようになります.

unsigned char sig[3];
clx::read(ifs, sig);
if (clx::combine(sig[0], sig[1], sig[2]) == clx::combine('G', 'I', 'F')) {
    unsigned char ver[3];
    clx::read(ifs, ver);
    switch (clx::combine(ver[0], ver[1], ver[2])) {
    case clx::combine('8', '7', 'a'):
        std::cout << "GIF version 87a." << std::endl;
        break;
    case clx::combine('8', '9', 'a'):
        std::cout << "GIF version 89a." << std::endl;
	break;
    default:
        std::cout << "GIF unknown version." << std::endl;
        break;
    }
}

これまでは,各 case に書く値はマクロだったり,メタ関数を書いちゃってみたり,諦めて直値を書いたりしていましたが,constexpr によって同じ関数で済ませる事ができるようになります.

constexpr は 複数の値を一つの変数に纏める関数 combine とメタ関数 combineN_ - Life like a clown の時に切実に欲しいなぁと思っただけなのでそれ以外の事はまだあまり考えきれてませんが,これまでバラついていたもの(マクロ,メタ関数)を関数などに統合できる可能性ができたので,またいろいろと検討できる余地が出てきそうです.