コンパイル時にビットマスク作成

cppllに流れていたネタ。

今、チェックサムを算出する関数を作っています。この関数は、処理の性質上チェック単位であるビット長に依存する定数を使います。例えば、unsigned shortならば、0xff00と0xffffです。ビット長のうち、半分をマスクしたり全てのビットに1を立てた定数です。32ビット長ならば、0xffff0000と、0xffffffffになります。

そこで相談なのですが、ビット長に合わせて上位をマスクしたり、全てのビットに1を立てたりするには、どうするのが良いと思われますか。処理のたびに毎回ビットシフトして定数を作るようなことはしたくなく、うまくすればコンパイル時に決定する定数を定義できると感じています。

こんな具合か。特に特殊化テンプレートは不要。「ビット長のうち、半分をマスクしたり全てのビットに1を立てた定数」はそれぞれfullmask, halfmaskメンバ参照でおk。上位nビットもコンパイル時に生成可能。

#include <iostream>

template<typename T>
struct bitmask {
    static const T fullmask = ~static_cast<T>(0);
    static const T halfmask = ~((T(1) << (sizeof(T) * 8 / 2)) - 1);
    template<unsigned char n>
    struct nmask {
        static const T mask = ~((T(1) << (sizeof(T) * 8 - n)) - 1);
    };
};

int main()
{
    std::cout << std::hex << bitmask<int>::fullmask << std::endl;
    std::cout << std::hex << bitmask<int>::halfmask << std::endl;
    std::cout << std::hex << bitmask<int>::nmask<2>::mask << std::endl;
    return 0;
}

ただし、ビット長チェックはしていない。

bitmask<char>::nmask<10>::mask

なんてやるとコンパイラに怒られる。もっとも型チェックしようがしまいがコンパイルエラーなので、どっちでもよさそうだが...

実数で同じ事できるようにならんかのぉ。