テンプレートを使ったコンパイル時数値計算
#include <iostream> #include <typeinfo> template <typename T, int length> struct array { typedef T element_type; element_type elements[length]; element_type& operator[](int offset) { return elements[offset]; } const element_type& operator[](int offset) const { return elements[offset]; } }; struct nil { typedef nil type; typedef nil next_type; }; template <int val> struct integer { typedef integer type; enum { value = val }; }; template <typename car_t, typename cdr_t> struct list { enum { value = car_t::value }; typedef cdr_t cdr_type; }; template <typename car_t, typename cdr_t> struct cons { typedef list<car_t, typename cdr_t::type > type; typedef cdr_t cdr_type; typedef cdr_t next_type; typedef car_t begin; typedef nil end; }; template <int current, int last, int distance = 1> struct range { typedef range self_type; typedef cons<integer<current>, typename range<current+distance, last, distance>::type > type; enum { min_value = current, max_value = last }; typedef type begin; typedef nil end; typedef typename type::cdr_type next_type; }; template <int last, int distance> struct range<last, last, distance> { typedef nil self_type; typedef nil begin; typedef nil next_type; typedef nil type; }; template <typename range_type, int offset> struct offset_of { enum { value = offset_of<typename range_type::next_type, offset-1>::value }; }; template <typename range_type> struct offset_of<range_type,0> { enum { value = range_type::begin::type::value }; }; template <> struct offset_of<nil,0> { enum { value = -1 }; }; template <typename functor_type, typename range_type, typename current_range_type = range_type> struct map_function { typedef map_function<functor_type, range_type, typename current_range_type::next_type> recursive_type; recursive_type recursive; functor_type functor; template <typename result_type> result_type operator()(result_type& result) const { const int current = offset_of<current_range_type, 0>::value; result[current] = functor(offset_of<range_type, current>::value); return recursive(result); } }; template <typename functor_type, typename range_type> struct map_function<functor_type, range_type, nil> { template <typename result_type> result_type operator()(result_type& result) const { return result; } }; struct identity { int operator()(int offset) const { return offset; } }; struct print_identity { int operator()(int offset) const { std::cout << "offset: " << offset << std::endl; return offset; } }; const int length = 100; typedef array<int, length> result_type; result_type result; typedef range<0, length> length_range; void print_array() { typedef map_function<print_identity, length_range> print_type; print_type func; func(result); } int main() { print_array(); for (int i = 0; i < length; ++i) std::cout << result[i] << std::endl; return 0; }
range
current: 初期値
last: 終了値
distance: オフセット1あたりの差分
range<0, 100, 1> で [0, 100)を表現する型になります。
んで、offset_of< range_type, index>::value でコンパイル時計算による値を取り出すことが出来ます。
これをひとつずつ展開する map_function があります。
map_function
functor_type: インデクスごとに呼ばれるファンクタ型。
range_type: mapする範囲。上で説明したrange型です。
で、map_functionのインスタンスのoperator()で呼び出しになります。引数は戻り値を受け取る配列です。
なので上のソースのidentity型をfunctorに、range_typeにrange<0, 100>を指定してmap_functionのoperator()を呼び出すと配列を0から99で初期化するようになります。
で、これを使って二重ループ代わりにして8bit * 8bitの掛け算テーブルでも作ろうかとしてたんですが・・・
コンパイルに膨大な時間がかかるようなので断念しました。
上のソースコードでもうちの2.4GHzのPen4、MinGW g++ 3.4.5で1分以上かかります。4.x系だと大分マシにはなりますが、大きくしていくと時間かかりすぎてお話にならない時間がかかるようでした・・・
実質的に使えるのは256テーブルでsin(), cos()テーブルの計算とかかなぁ・・・
まぁそれにしたって定数代入間ではつぶせない(=データセグメントに押し込むことは出来ない)ようなのでデータ量の節約になってるわけでもないんですよねぇ・・・