The reason you tend to only see one way of doing something is because the things that people actually use template meta-programming for are usually algorithmically trivial -- they just look complicated because they get mixed up with a load of type hackery and the oddities of C++ template syntax.
But sometimes (as Steve Jessop's answer shows) there really are multiple algorithms to calculate something, and you can implement any of them with templates.
As another example, here are two ways to evaluate pow(a,b)
(for small integer arguments):
Obvious:
// ----- Simple Way -----
template <int A, int B>
struct PowA {
typedef PowA<A,B-1> next;
enum {
value = A * next::value,
recursion_count = 1 + next::recursion_count
};
};
template <int A> struct PowA<A, 1> { enum { value = A, recursion_count = 0 }; };
template <int A> struct PowA<A, 0> { enum { value = 1, recursion_count = 0 }; };
Slightly less obvious:
// ----- Less Simple Way -----
template <int A, int B, int IsOdd> struct PowHelper;
template <int A> struct PowHelper<A, 0, 0> { enum { value = 1, recursion_count = 0 }; };
template <int A> struct PowHelper<A, 1, 1> { enum { value = A, recursion_count = 0 }; };
template <int A, int B>
struct PowHelper<A, B, 1> {
typedef PowHelper<A, B-1, 1> next;
enum {
value = A * next::value,
recursion_count = 1 + next::recursion_count
};
};
template <int A, int B>
struct PowHelper<A, B, 0> {
typedef PowHelper<A, B/2, ((B/2)&1)> next;
enum {
x = next::value,
value = x*x,
recursion_count = 1 + next::recursion_count
};
};
template <int A, int B>
struct PowB {
typedef PowHelper<A,B,(B & 1)> helper;
enum {
value = helper::value,
recursion_count = helper::recursion_count
};
};
And some code to let you check it:
// ----- Test -----
#include <iostream>
int main(int argc, char* argv[]) {
#define CHECK(X,Y) \
std::cout << ("PowA: " #X "**" #Y " = ") << \
PowA<(X),(Y)>::value << " (recurses " << \
PowA<(X),(Y)>::recursion_count << " times)" << std::endl; \
std::cout << ("PowB: " #X "**" #Y " = ") << \
PowB<(X),(Y)>::value << " (recurses " << \
PowB<(X),(Y)>::recursion_count << " times)" << std::endl;
CHECK(3,3)
CHECK(2,8)
CHECK(7,3)
CHECK(3,18)
#undef CHECK
return 0;
}