简体   繁体   English

C ++函数式编程代码片段

[英]C++ functional programming code snippets

I have been working on a project called: Functional Programming Features of C++11/14 (for one of my subjects at university). 我一直致力于一个名为C ++ 11/14的功能编程特性的项目(我的大学之一)。 There are several existing sources and similar presentations about such topics and I found one not so long ago which contained several code snippets that I haven't managed to understand completely (and somehow they can be connected to functional programming). 关于这些主题有几个现有的来源和类似的演示文稿,我发现不久前的一个包含几个我完全无法理解的代码片段(并且不知何故它们可以连接到函数式编程)。 Snippets A and B belonged to recursion and C belonged to lazy evaluation . 片段AB属于递归C属于懒惰评估 I'd like to share them with you below: 我想在下面与您分享:

Snippet A : 片段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 the point here compile time evaluation (in order to avoid runtime computations and improve performance)? 这里的重点是编译时评估(为了避免运行时计算并提高性能)? Or are there other advantages, too? 或者还有其他优点吗?

Snippet B : 代码片段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;
}

Same question applies as above. 同样的问题适用于上述。

And here is another snippet which is maybe similar: 这是另一个可能类似的片段:

Snippet C : 片段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 eager but the following will work." “该演示文稿说:C ++非常渴望,但以下内容将起作用。” Is its point that until I don't care about the given expressions I can tell the quantity of them? 重点是,在我不关心给定的表达式之前,我可以告诉它们的数量吗?

Please, be as specific and detailed as possible, and thank you very much for your patience and help in advance. 请尽可能详细和详细,非常感谢您的耐心和帮助。 :) :)

Snippet A 片段A.

This is called Template Metaprogramming , which is basically a technique using templates to generate code at compile time. 这称为Template Metaprogramming ,它基本上是一种使用模板在编译时生成代码的技术。 This increases run time performance, because the calculations aren't done at run time, but rather at compile time. 这会增加运行时性能,因为计算不是在运行时完成的,而是在编译时完成的。

Snippet A calculates the factorial of a given number at compile time: 代码片段A在编译时计算给定数字的阶乘:

template <int N>
struct Factorial {
    static int const val = N * Factorial<N - 1>::val;
};

This defines a struct Factorial as a template which takes an int . 这将struct Factorial定义为采用int的模板。 In that struct , there is a static const variable. 在该struct ,有一个static const变量。 The variable is static , so that you don't have to create an instance of Factorial to access it, you can just use Factorial::val instead of 变量是static ,因此您不必创建Factorial实例来访问它,您只需使用Factorial::val而不是

Factorial factorial;
factorial.val;

The variable is const because the factorial of a given number is always the same, and because the project won't compile if it isn't const , because the compiler has no way of knowing if you change the variable someplace else. 变量是const因为给定数字的阶乘总是相同的,并且因为如果项目不是const ,项目将不会编译,因为编译器无法知道您是否在其他地方更改了变量。

The variable has a value of N * Factorial<N - 1::val; 变量的值为N * Factorial<N - 1::val; , which basically multiplies N with the factorial of the previous number. ,它基本上将N乘以前一个数的阶乘。 This is because of how factorials are defined ( 3! = 2! * 3 = 1! * 2 * 3 = 1 * 2 * 3 = 6 ). 这是因为如何定义阶乘( 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 . 这为N = 0定义了一个完全专用的struct This is really important, or else the recursion used in the previous function will never stop. 这非常重要,否则前一个函数中使用的递归将永远不会停止。

Then, getting the factorial of a number N is easy, Factorial<N>::val . 然后,得到数N的阶乘是容易的, Factorial<N>::val This will be calculated at compile time. 这将在编译时计算。


Snippet B 代码片段B.

This is also Template Metaprogramming . 这也是Template Metaprogramming

 template <int ...> struct my_sum; 

This defines an empty template struct which takes an int... (a Parameter Pack ), so that it can be specialized (see next point). 这定义了一个空的模板struct ,它接受一个int... (一个Parameter Pack ),以便它可以被专门化(见下一点)。

 template <> struct my_sum <> { static const int value {0}; }; 

This specializes the struct my_sum , when no template arguments are given (this is because of the Parameter Pack , which can be empty, and so the template arguments will be empty when the Parameter Pack is expanded). 当没有给出模板参数时,这就特化了struct my_sum (这是因为Parameter Pack可以为空,因此扩展Parameter Pack时模板参数将为空)。 The value is static and const because of the same reasons as before, and it is 0 initialized using an initializer list (for an int , there is no difference between int i = 0; and int i{ 0 }; ). 由于与之前相同的原因,该value staticconst ,并且使用initializer list初始化为0 (对于intint i = 0;int i{ 0 }; )之间没有区别。

 template <int i, int ... tail> struct my_sum <i, tail ...> { static const int value = i + my_sum<tail ...>::value; }; 

This defines the struct my_sum as a template which takes 2 template arguments, an int and a int parameter pack. 这将struct my_sum定义为一个模板,它带有2个模板参数,一个int和一个int参数包。 This is used to get the value of the first value of a parameter pack, because you can't index a parameter pack (it's not an array). 这用于获取参数包的第一个值,因为您无法索引参数包(它不是数组)。 Then, value is initialized as i (the first value of the pack) plus the value of the other values as parameter pack, which is expanded (using the ... ): 然后, value被初始化为i (该包装件的第一值)加上value的其他值作为参数组,其被膨胀的(使用... ):

 int sum = my_sum<1, 2, 3>::value; 

This calls my_sum<int i, int... tail> , i is 1 and tail is 2, 3 . 这调用my_sum<int i, int... tail>i1tail2, 3 value is i + my_sum<tail...>::value , so it is 1 + my_sum<2, 3> . valuei + my_sum<tail...>::value ,所以它是1 + my_sum<2, 3> my_sum<2, 3> calls the same function again, 2 + my_sum<3>::value . my_sum<2, 3>再次调用相同的函数, 2 + my_sum<3>::value Now we have 1 + 2 + my_sum<3>::value . 现在我们有1 + 2 + my_sum<3>::value my_sum<3>::value calls again the same function, but now the parameter pack is empty! my_sum<3>::value再次调用相同的函数,但现在参数包是空的! So value is 1 + 2 + 3 + my_sum<>::value . 所以value1 + 2 + 3 + my_sum<>::value my_sum<>::value is 0 (as defined) and so value = 1 + 2 + 3 + 0 . my_sum<>::value0 (定义),因此value = 1 + 2 + 3 + 0


Snippet C 代码片段C.

The expression is evaluated, but the program doesn't crash because the expression when evaluated, is a double . 计算表达式,但程序不会崩溃,因为计算时的表达式是double Only when the expression is an int does it crash with a Integer division by zero exception . 只有当表达式为int ,它才会因Integer division by zero exception而崩溃。 If you were to do this: 如果你这样做:

 int zero = 0; double d = 1.0 / zero; 

Then d would have the value inf . 然后d将具有值inf

The function some_function is a template function which takes as template parameter a parameter pack. 函数some_function是一个模板函数,它将参数包作为模板参数。 Then it calls sizeof... which counts the elements in the parameter pack, and outputs it using std::cout . 然后它调用sizeof...来计算参数包中的元素,并使用std::cout输出它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM