異なる意味の値同士の演算の防止

2016-02-01 | [Programming]

C++ の typedef は,単に既存の型の別名を定義するだけで,新たな型を定義したりはしない. たいていの場合は,「元の型とまったく同様に使える」のは有用である. 例えば STL のコンテナの iterator は長ったらしい型になるので,それに短い別名をつけるのは合理的である.

しかし,値の意味が違うことを表すために型名を変えたいこともある.そのような場合には,違う意味の値同士でむやみに演算ができないようになっていたほうが便利である. 例えば「数独のグリッド上の Y 座標」と「数独で,グリッドのセルに書いてある数」は意味がまるで違い,この 2 つを足したりしていたら恐らくプログラムのミスである. また,この 2 種類の値を受け取る関数があったとして,引数を逆に指定していたりしてもプログラムのミスであろう. そのような場合にはコンパイルエラーになるようにするとバグを予防するのに役立ちそうである.

そのような目的のためには,単に struct で値をラップしてやればよい. しかし,それだけだと同じ型同士の演算もまどろっこしいため,それなりに便利に使えそうな型安全 typedef を作った.

実装

ここ にある. パズルソルバープロジェクトで使うため namespace がついているが,これは適当に変更すればよい.

少なくとも整数型については正しく動作するはずである.それ以外の型については試していないのでわからない. ただ,複雑な型についてこれを使うとオブジェクトのコピーが発生して面倒な気はする.

仕掛けは単純で,異なる typed_number 型同士の演算を明示的に禁止しているだけである. (delete 宣言を行わないと,typed_number<I, T> から I への変換関数が呼び出されることにより,演算ができてしまう)

#include "strict_typedef.h"


STRICT_TYPEDEF(int, int_x);
STRICT_TYPEDEF(int, int_y);

int ary[5];

int main()
{
	int_x a(1), b(2);
	int_y c(2);
	
	int x = a; // OK

	x = a + b; // OK

	a += 2; // OK

	x = a + 3; // OK

	
	ary[c] = x; // OK

	
	x = a + c; // NG!!

	b = c; // NG!!

	return 0;
}

仕様

これらの仕様は,ソースを適当に改変すればかなり好き勝手に変更することができる.