スポンサーリンク

| キーワード:

C++のソースコードに二進数を書くテンプレートを自作


///////////////////////////////////////////////////////////////
	
//頭に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対応してそうだからこんなもの意味がなくなるわけだけど。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: