Fragment A
This is called Template Metaprogramming , which is basically a method that uses templates to generate code at compile time. This increases performance at runtime because calculations are not performed at runtime, but rather at compile time.
Fragment A computes the factorial of a given number at compile time:
template <int N> struct Factorial { static int const val = N * Factorial<N - 1>::val; };
This defines the struct Factorial as a template that accepts an int . This struct has a static const variable. The variable is static , so you do not need to create an instance of Factorial to access it, you can just use Factorial::val instead
Factorial factorial; factorial.val;
The variable is const , because the factorial of a given number is always the same, and since the project will not compile if it is not const , because the compiler does not know whether you will change the variable somewhere else.
The variable is N * Factorial<N - 1::val; , which basically multiplies N by the factorial of the previous number. This is due to how factorials are determined ( 3! = 2! * 3 = 1! * 2 * 3 = 1 * 2 * 3 = 6 ).
template <> struct Factorial <0> { static int const val = 1; };
This defines a fully specialized struct for N = 0 . This is really important, otherwise the recursion used in the previous function will never stop.
Then getting the factorial of N easy, Factorial<N>::val . This will be calculated at compile time.
Fragment BThis is also Template Metaprogramming .
template <int ...> struct my_sum;
This defines an empty struct template that accepts int... (a Parameter Pack ) so that it can be specialized (see next point).
template <> struct my_sum <> { static const int value {0}; };
This specializes in struct my_sum when template arguments are not specified (this is due to the Parameter Pack , which may be empty, and therefore template arguments will be empty when expanding the Parameter Pack ), value is static and const for the same reasons as before , and 0 initializer list using the initializer list (for int there is no difference between int i = 0; and int i{ 0 }; ).
template <int i, int ... tail> struct my_sum <i, tail ...> { static const int value = i + my_sum<tail ...>::value; };
This defines struct my_sum as a template that accepts two template arguments, a packet of int and int parameters. This is used to get the value of the first value of the parameter package, since you cannot index the parameter package (this is not an array). Then value initialized as i (the first value of the package) plus the value other values ββin the form of a package of parameters, which expands (using ... ):
int sum = my_sum<1, 2, 3>::value;
This calls my_sum<int i, int... tail> , i is 1 and tail is 2, 3 . value - i + my_sum<tail...>::value , so this is 1 + my_sum<2, 3> . my_sum<2, 3> calls the same function again, 2 + my_sum<3>::value . Now we have 1 + 2 + my_sum<3>::value . my_sum<3>::value calls the same function again, but now the parameter package is empty! So, value - 1 + 2 + 3 + my_sum<>::value . my_sum<>::value 0 (as defined) and therefore value = 1 + 2 + 3 + 0 .
Fragment CThe expression is evaluated, but the program does not crash, because the expression during evaluation is double . Only when an int expression is broken with Integer division by zero exception . If you did this:
int zero = 0; double d = 1.0 / zero;
Then d will be inf .
The some_function function is a template function that takes a package of parameters as a template parameter. Then it calls sizeof... , which counts the elements in the parameter package and prints it using std::cout .