我看到其他答案很好地涵盖了替代方法,但没有人解释为什么需要enum
(or static const int
)。
首先,考虑以下非模板等效项:
#include <iostream>
int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n-1);
}
int main()
{
std::cout << Factorial(5) << std::endl;
std::cout << Factorial(10) << std::endl;
}
你应该能够很容易地理解它。然而,它的缺点是阶乘的值将在运行时计算,即在运行程序之后,编译器将执行递归函数调用和计算。
模板方法的想法是在编译时执行相同的计算,并将结果放入生成的可执行文件中。换句话说,您提供的示例可以解决类似问题:
int main()
{
std::cout << 120 << std::endl;
std::cout << 3628800 << std::endl;
}
但为了实现这一点,您必须“欺骗”编译器执行计算。为了做到这一点,您需要让它将结果存储在某个地方。
enum
正是为了做到这一点。我将尝试通过指出在那里不起作用的方法来解释这一点。
如果您尝试使用常规int
,它将无法正常工作,因为非静态成员 likeint
仅在实例化对象中才有意义。而且你不能像这样给它赋值,而是在构造函数中这样做。平原是int
行不通的。
您需要一些可以在未实例化的类上访问的东西。你可以试试static int
,但还是不行。clang
会给你一个非常简单的问题描述:
c.cxx:6:14: error: non-const static data member must be initialized out of line
static int value=n*Factorial<n-1>::value ;
^ ~~~~~~~~~~~~~~~~~~~~~~~
如果你真的把这些定义放在外面,代码会编译,但会产生两个0
s。那是因为这种形式将值的计算延迟到程序的初始化,并且不能保证正确的顺序。很可能Factorial<n-1>::value
在计算之前获得了 a ,因此0
被返回。此外,它仍然不是我们真正想要的。
最后,如果你把它放在static const int
那里,它将按预期工作。那是因为static const
必须在编译时计算,而这正是我们想要的。让我们再次输入代码:
#include <iostream>
template <unsigned n>
struct Factorial
{
static const int value=n*Factorial<n-1>::value ;
};
template <>
struct Factorial<0>
{
static const int value=1;
};
int main()
{
std::cout << Factorial<5>::value << std::endl;
std::cout << Factorial<10>::value << std::endl;
}
首先你实例化Factorial<5>
;static const int
强制编译器必须在编译器时计算它的值。实际上,它Factorial<4>
在必须计算另一个值时实例化类型。这一直持续到它Factorial<0>
到达可以在没有进一步实例化的情况下计算值的位置。
所以,这就是替代方式和解释。我希望它至少对理解代码有所帮助。
您可以将这种模板视为我在开头发布的递归函数的替代品。您只需替换:
return x;
与static const int value = ...
,
f(x-1)
与t<x-1>::value
,
- 并
if (n == 0)
具有专业化struct Factorial<0>
。
而对于它enum
本身,正如已经指出的那样,它在示例中用于强制执行与static const int
. 就像那样,因为所有enum
值都需要在编译时知道,所以实际上每个请求的值都必须在编译时计算。