【发布时间】:2020-01-02 00:31:00
【问题描述】:
我不理解以下行为。
以下代码,旨在在编译时计算阶乘,甚至无法编译:
#include <iostream>
using namespace std;
template<int N>
int f() {
if (N == 1) return 1; // we exit the recursion at 1 instead of 0
return N*f<N-1>();
}
int main() {
cout << f<5>() << endl;
return 0;
}
并抛出以下错误:
...$ g++ factorial.cpp && ./a.out
factorial.cpp: In instantiation of ‘int f() [with int N = -894]’:
factorial.cpp:7:18: recursively required from ‘int f() [with int N = 4]’
factorial.cpp:7:18: required from ‘int f() [with int N = 5]’
factorial.cpp:15:16: required from here
factorial.cpp:7:18: fatal error: template instantiation depth exceeds maximum of 900 (use ‘-ftemplate-depth=’ to increase the maximum)
7 | return N*f<N-1>();
| ~~~~~~^~
compilation terminated.
然而,在添加 N == 0 的特化(上面的模板甚至没有达到)时,
template<>
int f<0>() {
cout << "Hello, I'm the specialization.\n";
return 1;
}
即使从未使用特化,代码也会编译并给出正确的输出:
...$ g++ factorial.cpp && ./a.out
120
【问题讨论】:
-
如果它可以可能被调用,它必须存在。
-
在这种情况下,
constexpr int f(int N);(或 c++20 中的consteval)也可以。 -
旁注:
f<-1>()的结果是什么?由于它没有意义,我更喜欢 unsigned int 作为模板参数。我们不会阻止任何人写f<-1>(无论如何都会被转换为大整数),但至少我们会从一开始就表示我们实际上只期望非负值...... -
您得到了一个很好的答案,我无法有效地添加。我只想说明这是创建
constexpr的原因之一。 -
要数学完整:0 的阶乘定义为 1,所以你应该有
if constexpr(N == 0) return 1; else ...
标签: c++ templates recursion template-specialization factorial