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

C++ functional programming code snippets

本文关键字:代码 片段 编程 函数 C++      更新时间:2023-10-16

我一直在做一个名为:C++11/14的函数式编程特性的项目(我在大学的一门课)。关于这些主题,有几个现有的来源和类似的演示,我找到了一个不久前,它包含了几个我还没有完全理解的代码片段(不知何故,它们可以与函数式编程联系起来)。代码段AB属于递归,而C则属于lazy求值。我想在下面与大家分享:

代码段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;
}

这里的重点是编译时评估(为了避免运行时计算并提高性能)吗?或者还有其他优势吗?

代码段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;
}

上述问题同样适用。

这是另一个可能类似的片段:

代码段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;
}

"演示中说:C++很渴望,但以下内容会起作用。"这是不是意味着,在我不在乎给定的表达式之前,我可以说出它们的数量?

请尽可能具体和详细,并非常感谢您的耐心和提前提供的帮助。:)

代码段A

这被称为Template Metaprogramming,它基本上是一种在编译时使用模板生成代码的技术。这提高了运行时性能,因为计算不是在运行时完成的,而是在编译时完成的。

代码段A在编译时计算给定数字的阶乘:

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

这将struct Factorial定义为采用int的模板。在那个struct中,有一个static const变量。变量是static,因此您不必创建Factorial的实例来访问它,只需使用Factorial::val而不是

Factorial factorial;
factorial.val;

变量是const,因为给定数字的阶乘总是相同的,而且如果不是const,项目就不会编译,因为编译器无法知道你是否在其他地方更改了变量。

变量的值为N * Factorial<N - 1::val;,基本上将N与前一个数的阶乘相乘。这是因为阶乘是如何定义的(3! = 2! * 3 = 1! * 2 * 3 = 1 * 2 * 3 = 6)。

template <>
struct Factorial <0> {
    static int const val = 1;
};

这为N = 0定义了一个完全专用的struct。这一点非常重要,否则上一个函数中使用的递归将永远不会停止。

那么,得到一个数N的阶乘就很容易了,Factorial<N>::val。这将在编译时进行计算。


代码段b

这也是Template Metaprogramming

template <int ...>
struct my_sum;

这定义了一个空模板struct,它采用int...(一个Parameter Pack),这样它就可以被专门化(见下一点)。

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

当没有给定模板参数时,这专门用于struct my_sum(这是因为Parameter Pack可能是空的,因此当Parameter Pack展开时,模板参数将是空的)。由于与之前相同的原因,valuestaticconst,并且它是使用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;
};

这将struct my_sum定义为一个模板,它包含两个模板参数,一个int和一个int参数包。这用于获取参数包的第一个值的值,因为不能对参数包(它不是数组)进行索引。然后,value被初始化为i(包的第一个值)加上其他值的value作为参数包,该参数包被扩展(使用...):

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

这调用my_sum<int i, int... tail>i1tail2, 3valuei + my_sum<tail...>::value,所以它是1 + my_sum<2, 3>my_sum<2, 3>再次调用相同的函数2 + my_sum<3>::value。现在我们有了1 + 2 + my_sum<3>::valuemy_sum<3>::value再次调用相同的函数,但现在参数包为空!所以value就是1 + 2 + 3 + my_sum<>::value。CCD_ 57是CCD_ 58(如所定义的),因此CCD_。


代码段C

表达式被求值,但程序不会崩溃,因为求值时的表达式是double。只有当表达式是int时,它才会与Integer division by zero exception崩溃。如果你要这样做:

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

那么CCD_ 63将具有值CCD_。

函数some_function是以参数包作为模板参数的模板函数。然后它调用对参数包中的元素进行计数的sizeof...,并使用std::cout将其输出。