C ++ functional program code snippets

I am working on a project called C ++ 11/14 Programming Functionality (for one of my subjects at the university). There are several existing sources and similar presentations on such topics, and I found one not so long ago that contained several code fragments that I couldn’t fully understand (and somehow they can be connected to functional programming). Fragments A and B belonged to recursion, and C belonged to lazy evaluation. I would like to share it with you below:

Fragment A :

#include <iostream> template <int N> struct Factorial { static int const val = N * Factorial<N - 1>::val; }; template <> struct Factorial <0> { static int const val = 1; }; int main() { int factorial_of_6 = Factorial<6>::val; std::cout << factorial_of_6 << std::endl; return 0; } 

Was there a compile-time evaluation point (to avoid run-time calculations and improve performance)? Or are there other benefits?

Fragment B :

 #include <iostream> template <int ...> struct my_sum; template <> struct my_sum <> { static const int value {0}; }; template <int i, int ... tail> struct my_sum <i, tail ...> { static const int value = i + my_sum<tail ...>::value; }; int main() { int sum {my_sum<1, 2, 3, 4, 5>::value}; std::cout << sum << std::endl; return 0; } 

The same question applies as above.

And here is another snippet that might look like:

Fragment C :

 #include <iostream> template <typename... Args> void some_function (Args ...) { std::cout << sizeof...(Args) << std::endl; } int main() { some_function ("Every little thing gonna be alright...", 1.0 / 0.0); return 0; } 

"The presentation said: C ++ is impatient, but the following will work." Is it to the point that as long as I do not care about these expressions, I can tell their number?

Please be as specific and detailed as possible, and thank you very much for your patience and help in advance. :)

+7
c ++ c ++ 11 functional-programming recursion variadic-templates
source share
1 answer

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 B

This 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 C

The 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 .

+5
source share

All Articles