syntax highlight

Wednesday, 12 May 2010

Template metaprogramming V: Face to face

By now we have learned the basics for a nice template metaprogramming toolkit:

  • Loops with recursive template definitions
  • Conditionals with partial template specializations
  • Returns using typedefs

Unfortunately that's all you need for a Turing complete language, meaning now we have the power, bwahahaha! Mph, I'm sorry, back on topic, it means we can now create a fully functional and useful template metaprogramming device... for approximating e, nonetheless. Oh, you think that's not useful? Well though luck, that's all you get for now:

template <int N, int D> struct Frak {
    static const long Num = N;
    static const long Den = D;
};

template <class X, int N> struct ScalarMultiplication {
    static const long Num = N * X::Num;
    static const long Den = N * X::Den;
    typedef Frak<Num, Den> result;
};

template < class X1, class Y1 > struct SameBase {
	typedef typename ScalarMultiplication< X1, Y1::Den >::result X;
	typedef typename ScalarMultiplication< Y1, X1::Den >::result Y;
};

template <int X, int Y> struct MCD {
	static const long result = MCD<Y, X % Y>::result;
};

template <int X> struct MCD<X, 0> {
	static const long result = X;
};

template <class F> struct Simpl {
	static const long mcd = MCD<F::Num, F::Den>::result;
	static const long new_num = F::Num / mcd;
	static const long new_den = F::Den / mcd;
	typedef Frak< new_num, new_den > result;
};

template < class F1, class F2 > struct Sum {
	typedef SameBase<F1, F2> B;
	static const long Num = B::X::Num + B::Y::Num;
	static const long Den = B::Y::Den; // == B::X::Den
	typedef typename Simpl< Frak<Num, Den> >::result result;
};

template <int N> struct Fact {
	static const long result = N * Fact<N-1>::result;
};
template <> struct Fact<0> {
	static const long result = 1;
};

template <int N> struct E {
	// e = S(1/n!) = 1/0! + 1/1! + 1/2! + ...
	static const long Den = Fact<N>::result;
	typedef Frak< 1, Den > term;
	typedef typename E<N-1>::result next_term;
	typedef typename Sum< term, next_term >::result result;
};

template <> struct E<0> {
	typedef Frak<1, 1> result;
};

int main() {
    cout << (1.0 * E<8>::result::Num /  E<8>::result::Den) << endl;
    return 0;
}

Looking nice, isn't it? You should have all what's needed to understand what's going on there. Even more, almost everything has been explained in previous articles, with the exception of EqBase. But that's left as an exersice for the reader because the writer is too lazy.

If you think any part of the code requires clarification ask in the comments. Next, a long overdue topic: lists using template metaprogramming. Guaranteed to blow your mind into little pieces!

No comments:

Post a Comment