I see that the other answers are well suited for alternative approaches, but no one has explained why enum (or static const int ) is required.
First, consider the following equivalent without a pattern:
#include <iostream> int Factorial(int n) { if (n == 0) return 1; else return n * Factorial(n-1); } int main() { std::cout << Factorial(5) << std::endl; std::cout << Factorial(10) << std::endl; }
You should be able to understand this easily. However, the disadvantage is that the factorial value will be calculated at runtime, that is, after starting your program, the compiler will perform recursive function calls and calculations.
The idea of the template approach is to perform the same calculations at compile time and put the result in the resulting executable file. In other words, the example you provided allows something like this:
int main() { std::cout << 120 << std::endl; std::cout << 3628800 << std::endl; }
But for this you need to “trick” the compiler into doing the calculations. And for this you need to save the result somewhere.
enum exists for just that. I will try to explain this by indicating that it will not work there.
If you try to use a regular int , this will not work, because a non-static member such as int only makes sense in an instance of the object. And you cannot assign it a value like this, but instead do it in the constructor. A simple int will not work.
Instead, you will need something that would be available for the uninstalled class. You can try static int , but it still doesn't work. clang will give you a pretty simple description of the problem:
c.cxx:6:14: error: non-const static data member must be initialized out of line static int value=n*Factorial<n-1>::value ; ^ ~~~~~~~~~~~~~~~~~~~~~~~
If you really place these definitions out of turn, the code will be compiled, but this will result in two 0 s. This is due to the fact that this form delays the calculation of values for initializing the program and does not guarantee the correct order. It is likely that a Factorial<n-1>::value was obtained before the calculation, and thus 0 was returned. Moreover, this is still not what we really want.
Finally, if you put a static const int there, it will work as expected. This is because the static const needs to be computed at compile time, and that is exactly what we want. Let us enter the code again:
#include <iostream> template <unsigned n> struct Factorial { static const int value=n*Factorial<n-1>::value ; }; template <> struct Factorial<0> { static const int value=1; }; int main() { std::cout << Factorial<5>::value << std::endl; std::cout << Factorial<10>::value << std::endl; }
First you create an instance of Factorial<5> ; static const int forces the compiler to compute its value at compiler time. In fact, it creates an instance of type Factorial<4> when it needs to calculate a different value. And this goes until it hits Factorial<0> , where the value can be calculated without additional instances.
So that was an alternative way and explanation. I hope this was at least a little useful for understanding the code.
You can think of patterns like replacing the recursive function that I posted at the beginning. You just replace:
return x; with static const int value = ... ,f(x-1) with t<x-1>::value ,- and
if (n == 0) with specialization struct Factorial<0> .
And for enum itself, as already mentioned, it was used in this example to provide the same behavior as static const int . It is like all enum values should be known at compile time, so effectively every requested value should be computed at compile time.