21

我在这里找到了一个代码Printing 1 to 1000 without loop or conditionals

有人可以解释一下编译时递归是如何工作的吗,在谷歌中找不到

// compile time recursion
template<int N> void f1()
{ 
    f1<N-1>(); 
    cout << N << '\n'; 
}

template<> void f1<1>() 
{ 
    cout << 1 << '\n'; 
}


int main()
{
    f1<1000>();
}

谢谢!

4

5 回答 5

12

它使用(调用等)f1<N>的递减值重复实例化模板。显式特化结束递归:一旦变为 1,编译器将选择特化函数而不是模板函数。Nf1<N>()f1<N-1>N==1N

f1<1000>()导致编译器实例化f1<N>999 次(不计入对 的最终调用f1<1>)。这就是编译大量使用模板元编程技术的代码可能需要一段时间的原因。

整个事情在很大程度上依赖于编译器的优化技能——理想情况下,它应该完全删除递归(它只用作for使用模板模拟循环的技巧)。

于 2011-03-11T14:32:42.310 回答
2

它在概念上的工作方式与运行时递归几乎相同。f1<1000>调用f1<999>,然后打印出 1000。f1<999>调用f1<998>,然后打印出 999,等等。一旦它达到 1,模板特化就作为中止递归的基本情况。

于 2011-03-11T14:32:49.277 回答
1

很简单,每个模板实例化都会使用更改的参数创建一个新函数。就像你定义的那样:f1_1000()、f1_999() 等等。

每个函数调用名称中少 1 的函数。由于有一个不同的模板,而不是递归的,来定义 f1_1() 我们也有一个停止情况。

于 2011-03-11T14:33:05.913 回答
1

这不能保证是纯编译时递归。编译器必须为从 2 到 1000 的所有参数值实例化函数f1(),并且它们将相互调用。

然后编译器可能会看到这些调用可以变成一系列cout << ...语句。也许它消除了调用,也许不是——这取决于编译器。从 C++ 的角度来看,这是一个函数调用链,只要不改变行为,编译器就可以做任何事情。

于 2011-03-11T14:45:28.640 回答
1

你在这里解释了阶乘计算。

顺便说一句,请注意您的函数不适用于负数。

于 2011-03-11T14:47:41.603 回答