las*_*zso 6 c++ recursion functional-programming variadic-templates c++11
我一直致力于一个名为C++ 11/14的功能编程特性的项目(我的大学之一).关于这些主题有几个现有的来源和类似的演示文稿,我发现不久前的一个包含几个我完全无法理解的代码片段(并且不知何故它们可以连接到函数式编程).片段A和B属于递归,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++非常渴望,但以下内容将起作用." 重点是,在我不关心给定的表达式之前,我可以告诉它们的数量吗?
请尽可能详细和详细,非常感谢您的耐心和帮助.:)
片段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)
这定义了一个完全专业化struct
的N = 0
.这非常重要,否则前一个函数中使用的递归将永远不会停止.
然后,获得数字的阶乘N
很容易Factorial<N>::val
.这将在编译时计算.
这也是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
扩展).的value
IS static
和const
的,因为同样的理由,之前,并且它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>
,i
是1
和tail
是2, 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
再次调用相同的函数,但现在参数包是空的!所以value
是1 + 2 + 3 + my_sum<>::value
.my_sum<>::value
是0
(定义)等等value = 1 + 2 + 3 + 0
.
表达式被计算,但程序不会崩溃,因为计算时的表达式是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
.