コンパイラ電卓

すごく実用性のないものを作った

#include <iostream>

//a + b
template <int a,int b>
struct Adder
{
	enum {value = a + b };
};

//num!
template <int num,int unused>
struct Factor
{
	enum {value = num * Factor<num - 1,unused>::value};
};
template <int unused>
struct Factor<0,unused>
{
	enum {value = 1};
};

template <int num,int power>
struct Power
{
	enum {value = num * Power<num,power - 1>::value};
};
template <int num>
struct Power<num,0>
{
	enum {value = num};
};

//a % b
template <int a,int b>
struct Remainder
{
	enum {value = A % B};
};

//a / b
template <int a,int b>
struct Divide
{
	enum {value = a / b};
};

//a * b
template <int a,int b>
struct Multiple
{
	enum {value = a * b};
};

int main()
{
#ifndef A
#define A 1
#endif

#ifndef B
#define B 1
#endif

	std::cout << STAT<A,B>::value;

	return 0;
}


コンパイル時にマクロで引数を与えてやると

c:\Users\hiroya\Documents\Visual Studio 2008\Projects\TestProject>cl main.cpp -D
STAT=Adder -DA=1 -DB=2
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\xlocale(342) : warning C
4530: C++ 例外処理を使っていますが、アンワインド セマンティクスは有効にはなりま
せん。/EHsc を指定してください。
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj

c:\Users\hiroya\Documents\Visual Studio 2008\Projects\TestProject>main.exe
3

c:\Users\hiroya\Documents\Visual Studio 2008\Projects\TestProject>cl main.cpp -D
STAT=Power -DA=2 -DB=5
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE\xlocale(342) : warning C
4530: C++ 例外処理を使っていますが、アンワインド セマンティクスは有効にはなりま
せん。/EHsc を指定してください。
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj

c:\Users\hiroya\Documents\Visual Studio 2008\Projects\TestProject>main.exe
64

ちなみに、アセンブラファイルを出力させてみると

; 1035 : 	std::cout << STAT<A,B>::value;

  00003	6a 40		 push	 64			; 00000040H
  00005	8b 0d 00 00 00
	00		 mov	 ecx, DWORD PTR __imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
  0000b	ff 15 00 00 00
	00		 call	 DWORD PTR __imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z

ということで、生成される実行ファイルはちゃんと定数をpushするだけになってる。


もともとはsinとかcosとかをコンパイル時に実行できたらいいなと思って書いていたので、
↓みたいなものも書いてたんだけど

template <double num,int recursionCount>
struct Sin
{
	enum {value = Sin<num,recursionCount - 1>::value +
		(!recursionCount) * (1 / (Factor<recursionCount * 2 + 1,1>::value)) * Power<num,recursionCount * 2 + 1>::value};

};

template <double num>
struct Sin<num,0>
{
	enum {value = num};
};

書き終わってから、「コンパイル時に小数って普通にやったら駄目なんじゃないの」ってことに気づいてみたり。
なので上のコードは一度も実行してないというか、できないというか、デバッグもできてないしもしかしたら再帰がとまらないかもしれない。


どうやらコンパイル時に小数を扱うのは、Boost/MPLにちょっとあるみたいなんだけど、実装ほぼ空だった。
BoostVaultにはもうちょっとましなのがあるらしいので、試してみようかな。