4

我正在玩一点constexpr递归并尝试查看它是如何编译的,但我不明白在哪种情况下gcc选择在编译时或运行时计算递归。

我正在使用以下阶乘计算代码:

#include <iostream>

constexpr unsigned int factorial(unsigned int i)
{
  return i > 0 ? i*factorial(i-1) : 1;
}

int main(void)
{
  std::cout << factorial(X) << std::endl;
}

我改变x了阶乘中的值。

  • 在没有优化的情况下编译时,表达式不会在编译时计算。
  • 使用-O1标志编译时,在编译时仍不计算表达式。
  • 使用-O2,表达式在编译时计算 if x < 9。在此值之后,阶乘以循环的形式内联实现。更改-fconstexpr-depth标志的值不会改变任何事情。
  • 使用-O3,表达式是在编译时计算的if x < 7。在这个值之后,阶乘通过 x86 xmm 扩展实现内联。
  • 如果我将乘积更改为阶乘函数中的总和,我将获得最多10000或更多的编译时间计算,并且减少或增加 的值-fconstexpr-depth不会改变任何内容。

有谁知道 gcc 4.7 将递归函数实现为编译时或运行时的规则是什么?

4

2 回答 2

2

constexpr仅在编译时需要时才保证在编译时进行评估。例如,这保证在编译时计算,因为enum值必须是常量:

enum { VALUE = factorial(X) };
cout << VALUE << endl;

在编译时不需要它的任何情况下,它与将其声明为 具有相同的效果inline:它只是一个提示,编译器可以自由地做它想做的事情。

就像inline,现在大多数编译器都会完全忽略你的提示。出于性能原因,编译器希望即使您没有要求它也能够内联事物,并且有自己的算法来确定什么时候值得,什么时候不值得,那么为什么还要费心查看inline关键字呢?

于 2013-01-20T04:31:36.283 回答
1

声明一个函数constexpr并不意味着它将在编译时进行评估。这意味着它可用于计算编译时所需的值。在任何其他情况下,它只是一个普通函数,它将在运行时评估,除非编译器确定在编译时评估它满足“as-if”规则,并且值得这样做。

换句话说,如果您没有constexpr声明阶乘函数,我希望您会发现完全相同的编译时/运行时执行模式。

于 2013-01-20T00:59:41.593 回答