Constexpr因子编译结果在VS2015和GCC 5.4.0中

时间:2017-05-02 15:14:28

标签: c++ c++11 gcc visual-studio-2015 constexpr

想知道以下是否让任何人感到惊讶,就像我一样? Alex Allain关于使用constexpr的文章here显示了以下因子示例:

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

并声明:

  

现在你可以使用factorial(2),当编译器看到它时,它可以   优化掉调用并在编译时完全进行计算   时间。

我在VS2015中在发布模式下尝试了这一点,并在(/ Ox)上进行了全面优化,并在调试器中查看了程序集,并看到在编译时没有的因子计算。 / p>

使用GCC v5.4.0和--std = C ++ 14,我必须在编译时执行计算之前使用/ O2或/ O3。我很惊讶,在编译时没有使用/ O计算。

主要问题是:为什么VS2015在编译时没有执行此计算?

3 个答案:

答案 0 :(得分:5)

这取决于函数调用的上下文。

例如,以下显然永远无法在编译时计算:

int x;
std::cin >> x;
std::cout << factorial(x);

另一方面,这个上下文在编译时需要答案:

class Foo {
    int x[factorial(4)];
};

constexpr函数只保证在编译时被评估,如果它们是从constexpr上下文调用的;否则由编译器决定是否在编译时进行评估(假设这样的优化是可能的,同样,取决于上下文)。

答案 1 :(得分:3)

你必须在const表达式中使用它,如:

 constexpr auto res = factorial(2);

否则计算可以在运行时完成。

答案 2 :(得分:1)

constexpr 既不必要足以编译函数的时间评估。

这是不够的,即使除了参数显然也必须是常量表达式这一事实。即使这是真的,符合标准的编译器也不必在编译时对其进行评估。如果它在constexpr上下文中,则只需在编译时进行评估。例如,将计算结果分配给constexpr变量,或将值用作数组大小,或者作为非类型模板参数。

另一点是,编译器完全能够在编译时评估事物,即使没有constexpr。关于这一点存在很多困惑,并且不清楚为什么。 constexpr函数的编译时评估从根本上归结为不断传播,编译器一直在进行这种优化:https://godbolt.org/g/Sy214U

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n-1);
}

int foo() { return factorial(5); }

在gcc 6.3上用O3(和14)产生:

foo():
        mov     eax, 120
        ret

本质上,在通过将constexpr函数分配给另一个constexpr变量来绝对强制编译时评估的特定情况之外,编译时评估更多地与优化器的质量相关而不是标准。 / p>