/////////////////////////////////////////////////////////////// //頭に0がついて8進数表記になったときに呼び出される //第一テンプレート引数:二進数に直したい数(8進数表記で渡された) //第二テンプレート引数:何桁シフトするか(演算に使用・呼び出し時は0) //第三テンプレート引数:何桁の二進数が入力されたか template <int N,int shift,int digit> struct ToDec8toBin{ enum { Val = ( ToDec8toBin<N/8,shift+1,digit>::Val ) + ( N % 2 << shift ), }; }; template <int N,int digit> struct ToDec8toBin<N,digit,digit>{ enum { Val = 0, }; }; ///////////////////////////////////////////////////////////// //頭に0がつかず10進数表記になったときに呼び出される template <int N, int shift, int digit> struct ToDec10toBin{ enum { Val = (ToDec10toBin<N / 10, shift + 1, digit>::Val) + (N % 2 << shift), }; }; template <int N, int digit> struct ToDec10toBin<N, digit, digit>{ enum { Val = 0, }; }; ///////////////////////////////////////////////////////////// //C++で二進数表記をするための関数・エントリポイント template <bool Cond,int N,int digit> struct ToDecCore; //頭に0がついて8進数になっているときはこちらを呼び出す template <int N, int digit> struct ToDecCore<true, N,digit>{ enum { Val = ToDec8toBin<N,0,digit>::Val,}; }; //頭に0がついていないときは10進数からの変換を行う template <int N, int digit> struct ToDecCore<false, N,digit>{ enum { Val = ToDec10toBin<N, 0, digit>::Val,}; }; //真のエントリポイント(4bit) template <int H> struct ToDecimal4{ enum { Val = ToDecCore < H <= 0111, H, 4>::Val, }; }; //真のエントリポイント(8bit) template <int HH,int HL> struct ToDecimal8{ enum { Val = (ToDecCore < HH <= 0111, HH, 4>::Val << 4 )+ ToDecCore < HL <= 0111, HL, 4>::Val }; }; //真のエントリポイント(16bit) //4ビットずつ区切って渡す template <int B4, int B3,int B2, int B1> struct ToDecimal16{ enum { Val = (ToDecCore < B4 <= 0111, B4, 4>::Val << 12) + (ToDecCore < B3 <= 0111, B3, 4>::Val << 8) + (ToDecCore < B2 <= 0111, B2, 4>::Val << 4) + ToDecCore < B1 <= 0111, B1, 4>::Val }; }; //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// int _tmain(int argc, _TCHAR* argv[]) { printf("1101 0010 0101 0011:%d\n", ToDecimal16<1101, 0010, 0101, 0011>::Val); getchar(); return 0; }
探せばいくらでも出てきそうだが勉強のため自作。
やってることはテンプレートを再帰してるだけ。
ただし、C/C++は数値の頭がゼロだと8進数表記にするというヨクワカラナイ言語仕様を持っているため、1000以降と0111以前で処理を分岐している。「C++テンプレートテクニック」に書いてあったものを好みに改良した。
多分、4桁ずつじゃなく8桁ずつ書いた方が使いやすいという人の方が多いのだろうが、個人的には4桁くらいで区切らないと読みにくい。
Boostとか、Cのマクロとか、確か同じような処理をする機能が提供されていたと思う。
ただ、Boostは一つのことをやりたいだけに導入するにはあまりにでかすぎる。
ちゃんと名前空間で囲って、エントリポイントをさらにconstexprした関数でくくれば実用的になると思う。
VC++にはconstexprないけど。というかconstexprtまで対応してるなら0b対応してそうだからこんなもの意味がなくなるわけだけど。