【问题标题】:How compile time recursion works?编译时递归如何工作?
【发布时间】:2011-07-13 13:09:28
【问题描述】:

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

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

// 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>();
}

谢谢!

【问题讨论】:

  • 其实有个窍门,特化是有条件的,虽然没有if关键字...
  • 有没有比运行时递归快得多的经验法则?
  • 用它代替常规递归有什么好处?

标签: c++ compile-time


【解决方案1】:

它反复实例化 f1&lt;N&gt; 模板,并减少 N 的值(f1&lt;N&gt;() 调用 f1&lt;N-1&gt; 等等)。 N==1 的显式特化结束递归:一旦 N 变为 1,编译器将选择特化函数而不是模板函数。

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 为什么打印的是从 0 到 1000 而不是从 1000 到 0?
    • @VextoR:那是因为它首先调用 f1,然后打印。
    • @VextoR 因为它在实例化下一个模板后将N 输出到控制台。
    • @sharptooth == 999?它应该打印“999”吗?
    • @VextoR:不,它首先调用f1&lt;999&gt;(),然后打印1000。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        您已经解释了阶乘计算here

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-26
          • 1970-01-01
          • 2012-02-04
          • 1970-01-01
          • 2010-12-19
          • 1970-01-01
          • 2014-04-17
          相关资源
          最近更新 更多