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

las*_*zso 6 c++ recursion functional-programming variadic-templates c++11

我一直致力于一个名为C++ 11/14的功能编程特性的项目(我的大学之一).关于这些主题有几个现有的来源和类似的演示文稿,我发现不久前的一个包含几个我完全无法理解的代码片段(并且不知何故它们可以连接到函数式编程).片段AB属于递归,C属于懒惰评估.我想在下面与您分享:

片段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;
}
Run Code Online (Sandbox Code Playgroud)

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

代码片段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;
}
Run Code Online (Sandbox Code Playgroud)

同样的问题适用于上述.

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

片段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;
}
Run Code Online (Sandbox Code Playgroud)

"该演示文稿说:C++非常渴望,但以下内容将起作用." 重点是,在我不关心给定的表达式之前,我可以告诉它们的数量吗?

请尽可能详细和详细,非常感谢您的耐心和帮助.:)

Rak*_*111 5

片段A.

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

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

template <int N>
struct Factorial {
    static int const val = N * Factorial<N - 1>::val;
};
Run Code Online (Sandbox Code Playgroud)

这将a定义struct Factorial为一个模板int.在那里struct,有一个static const变量.变量是static,因此您不必创建Factorial访问它的实例,您可以使用Factorial::val而不是

Factorial factorial;
factorial.val;
Run Code Online (Sandbox Code Playgroud)

变量是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;
};
Run Code Online (Sandbox Code Playgroud)

这定义了一个完全专业化structN = 0.这非常重要,否则前一个函数中使用的递归将永远不会停止.

然后,获得数字的阶乘N很容易Factorial<N>::val.这将在编译时计算.


代码片段B.

这也是Template Metaprogramming.

template <int ...>
struct my_sum;
Run Code Online (Sandbox Code Playgroud)

这定义了一个空模板struct,它采用int...(a Parameter Pack),因此它可以是专用的(见下一点).

template <>
struct my_sum <> {
    static const int value {0};
};
Run Code Online (Sandbox Code Playgroud)

这个专业的struct my_sum,没有给出模板参数时(这是因为Parameter Pack,它可以是空的,所以当模板参数将是空的Parameter Pack扩展).的valueIS staticconst的,因为同样的理由,之前,并且它0使用一个初始化initializer list(对于int,之间不存在差异int i = 0;int i{ 0 };).

template <int i, int ... tail>
struct my_sum <i, tail ...> {
    static const int value = i + my_sum<tail ...>::value;
};
Run Code Online (Sandbox Code Playgroud)

这将struct my_sum模板定义为一个模板,它带有2个模板参数,int一个int参数包和一个参数包.这用于获取参数包的第一个值,因为您无法索引参数包(它不是数组).然后,value初始化为i(包的第一个值)加上value其他值作为参数包,它被展开(使用...):

int sum = my_sum<1, 2, 3>::value;
Run Code Online (Sandbox Code Playgroud)

这叫my_sum<int i, int... tail>,i1tail2, 3.value就是i + my_sum<tail...>::value这样1 + my_sum<2, 3>.my_sum<2, 3>再次调用相同的函数2 + my_sum<3>::value.现在我们有1 + 2 + my_sum<3>::value.my_sum<3>::value再次调用相同的函数,但现在参数包是空的!所以value1 + 2 + 3 + my_sum<>::value.my_sum<>::value0(定义)等等value = 1 + 2 + 3 + 0.


代码片段C.

表达式被计算,但程序不会崩溃,因为计算时的表达式是a double.只有表达式是一个int它崩溃了Integer division by zero exception.如果你这样做:

int zero = 0; 
double d = 1.0 / zero;
Run Code Online (Sandbox Code Playgroud)

然后d就会有价值inf.

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