【问题标题】:Fibonacci and 'if constexpr'斐波那契和'if constexpr'
【发布时间】:2017-12-23 18:58:11
【问题描述】:

请考虑以下代码:

template<int nIndex>
int Fibonacci()
{
    if constexpr (nIndex == 0) return 0;
    if constexpr (nIndex == 1) return 1;

    static_assert(nIndex >= 0, "Invalid index passed to Fibonacci()");
    return Fibonacci<nIndex - 1>() + Fibonacci<nIndex - 2>();
}

int main()
{
    Fibonacci<3>(); // 2
    //Fibonacci<-1>();  // Fires assertion 

    return 0;
}

当我在 VS2017 中运行它时,编译器输出:

error C2338: Invalid index passed to Fibonacci()
note: see reference to function template instantiation 'int Fibonacci<-1>(void)' being compiled
note: see reference to function template instantiation 'int Fibonacci<1>(void)' being compiled
note: see reference to function template instantiation 'int Fibonacci<3>(void)' being compiled

这不是我所期望的;我希望结果是 2。我在这里错误地使用了if constexpr 吗?

此外,我不理解编译器的诊断信息。

Fib(3) = Fib(2)              + Fib(1)
       = Fib(1) + Fib(0)
       = 1      + 0          + 1
       = 2

那么为什么编译器会认为 Fib(-1) 被调用了呢?

【问题讨论】:

  • 好的,所以我在第二个 if constexprelse 和最后的 return 语句之前放置了一个 else 和一个 else,它可以工作。但是我在这里遗漏了一些基本的东西,我认为在编译器点击第一个 return 之后它不会执行任何其他操作......还是我误解了 if constexpr
  • if constexpr 两个分支之外的代码将无条件编译,因此即使在您的代码变体中,Fibonacci&lt;nIndex - 1&gt;()Fibonacci&lt;nIndex - 2&gt; 也应编译为 nIndex == 0nIndex == 1。跨度>
  • 但是为什么在 'if constexpr (nIndex == 0) return 0;' 中的 return 语句之后编译没有“停止”;我的意思是,我可以看到它没有,但我不明白为什么...
  • 我不知道这种行为背后的原因是什么。

标签: c++ templates if-statement c++17 constexpr


【解决方案1】:

那么为什么编译器会认为 Fib(-1) 被调用了呢?

它没有;它认为它已被实例化(或者更具体地说,Fibonacci&lt;-1&gt; 已被实例化)。

你想要的是条件实例化。这只有在实例化模板的语句本身由if constexpr 语句控制时才能实现:

template<int nIndex>
int Fibonacci()
{
    static_assert(nIndex >= 0, "Invalid index passed to Fibonacci()");

    if constexpr (nIndex == 0) return 0;
    else if constexpr (nIndex == 1) return 1;
    else
      return Fibonacci<nIndex - 1>() + Fibonacci<nIndex - 2>();
}

如果nIndex 为0 或1,那么最终return 语句中的代码不会导致模板被实例化。

【讨论】:

  • 好的,所以你的意思是当执行Fib(3)时,编译器知道这是Fib(2) + Fib(1),所以它似乎首先执行Fib(1) ,并且当这样做不会在if constexpr (nIndex == 0) return 0; 中的第一个返回语句之后“停止”,而是继续通过return Fibonacci&lt;nIndex - 1&gt;() + Fibonacci&lt;nIndex - 2&gt;(); 执行 Fib(0) + Fib(-1),后者是编译器的输出 - 我理解正确吗?
  • @Wad:不。这与执行的内容无关。这是关于什么被实例化。你继续输入Fib(1),而实际发生的是Fibonacci&lt;1&gt;()。这些不是一回事。后者是模板实例化。如果语句Fibonacci&lt;-1&gt; 出现在程序中的任何地方,那么由于静态断言,程序将无法编译。
  • 是的,我明白了。好的,你是说当我实例化Fibonacci&lt;3&gt;() 时,会导致Fibonacci&lt;2&gt;()Fibonacci&lt;1&gt;() 的实例化。因此,从我的编译器输出看来,Fibonacci&lt;1&gt;() 然后在Fibonacci&lt;2&gt;() 之前首先被实例化,由于我的原始代码中没有else 语句,导致Fibonacci&lt;0&gt;()Fibaonacci&lt;-1&gt;() 被实例化......因此我的错误。这是正确的理解吗?
猜你喜欢
  • 2011-02-16
  • 2012-12-29
  • 1970-01-01
  • 2015-07-25
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 2014-05-23
相关资源
最近更新 更多