トレイト・クラス
トレイト・クラスと呼ばれる、C++のイディオムを使うと、型を返す関数(型関数)が作れます。型関数はテンプレートを利用して実現されていて、コンパイル時に実行されることになります。下の例だと、構造体input_typeがトレイト・クラスにあたり、InputType(型,引数の数)が型を返します。
template<typename T, int i> struct input_type; #define InputType(T, i) typename input_type<T, i>::type #define Domain(F) InputType(F, 0)
Domain(F)のFは引数が同じ型の関数ポインタか関数オブジェクトが入り、Domain(F)は関数の引数の型を返します(数学で言うところの定義域になる)。input_typeを型ごとに定義することでDomain(F)が返す型を分岐させることができます。例えば、2乗を計算する関数オブジェクトstruct sq
template<typename T> struct sq { T operator() (const T& x) { return x * x; } }; template<typename T> struct input_type<sq<T>, 0> { typedef T type; }; template<typename T> struct input_type<T(*)(const T&), 0> { typedef T type; }; template<typename T> T square(const T& x) { return x * x; }
このようにして定義した型関数は、テンプレート関数の中で使うことができます。
template<typename F, typename N> Domain(F) power_unary(Domain(F) x, N n, F f) { while(n != N(0)) { x = f(x); n = n - N(1); } return x; } #include <cassert> int main(void) { int n ; int x ; for(n = 1; n < 5; n++) { for(x = 2; x < 5; x++) { int tmp = power_unary(x, n-1, sq<int>()); assert(power_unary(x, n, sq<int>()) == tmp * tmp); assert(power_unary(x, n, square<int>) == tmp * tmp); } } return 0; }
ここで使ったコードの完全なものはこのリンクから得ることができます。