简体   繁体   English

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

[英]Constexpr Factorial Compilation Results in VS2015 and GCC 5.4.0

Wondering if the following surprises anyone, as it did me? 想知道以下是否让任何人感到惊讶,就像它对我一样? Alex Allain's article here on using constexpr shows the following factorial example: Alex Allain 在这里使用constexpr的文章显示了以下因子示例:

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

And states: 并指出:

Now you can use factorial(2) and when the compiler sees it, it can optimize away the call and make the calculation entirely at compile time. 现在你可以使用factorial(2),当编译器看到它时,它可以优化掉调用并在编译时完全进行计算。

I tried this in VS2015 in Release mode with full optimizations on (/Ox) and stepped through the code in the debugger viewing the assembly and saw that the factorial calculation was not done at compilation. 我在VS2015中以释放模式尝试了这一点,并对(/ Ox)进行了全面优化,并逐步查看调试器中查看程序集的代码,并看到在编译时没有进行因子计算。

Using GCC v5.4.0 with --std=C++14, I must use /O2 or /O3 before the calculation is performed at compile time. 使用GCC v5.4.0和--std = C ++ 14,我必须在编译时执行计算之前使用/ O2或/ O3。 I was surprised thought that using just /O the calculation did not occur at compilation time. 我很惊讶,在编译时没有使用/ O计算。

Main main question is: Why is VS2015 not performing this calculation at compilation time? 主要问题是:为什么VS2015在编译时没有执行此计算?

It depends on the context of the function call. 它取决于函数调用的上下文。

For example, the following obviously could never be calculated at compile time: 例如,以下显然永远无法在编译时计算:

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

On the other hand, this context would require the answer at compile time: 另一方面,这个上下文需要在编译时得到答案:

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

constexpr functions are only guaranteed to be evaluated at compile time if they are called from a constexpr context; constexpr函数只保证在编译时被评估,如果它们是从constexpr上下文调用的; otherwise it is up to the compiler to choose whether or not to eval at compile time (assuming such an optimization is possible, again, depending on the context). 否则由编译器决定是否在编译时进行评估(假设这样的优化是可能的,同样取决于上下文)。

You have to use it in const expression, as: 你必须在const表达式中使用它,如:

 constexpr auto res = factorial(2);

else computation can be done at runtime. 否则计算可以在运行时完成。

constexpr is neither necessary nor sufficient to compile time evaluation of a function. constexpr 不必要不足以编译函数的时间评估。

It's not sufficient, even aside from the fact that the arguments obviously also have to be constant expressions. 这是不够的,即使除了参数显然也必须是常量表达式这一事实。 Even if that is true, a conforming compiler does not have to evaluate it at compile time. 即使这是真的,符合标准的编译器也不必在编译时对其进行评估。 It only has to be evaluated at compile time if it is in a constexpr context. 如果它在constexpr上下文中,则只需在编译时进行评估。 Such as, assigning the result of the computation to a constexpr variable, or using the value as an array size, or as a non-type template parameter. 例如,将计算结果分配给constexpr变量,或将值用作数组大小,或者作为非类型模板参数。

The other point, is that the compiler is completely capable of evaluating things at compile time, even without constexpr. 另一点是,编译器完全能够在编译时评估事物,即使没有constexpr。 There is a lot of confusion about this, and it's not clear why. 对此存在很多困惑,目前尚不清楚原因。 compile time evaluation of constexpr functions fundamentally just boils down to constant propagation, and compilers have been doing this optimization since forever: https://godbolt.org/g/Sy214U . 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); }

On gcc 6.3 with O3 (and 14) yields: 在gcc 6.3上用O3(和14)产生:

foo():
        mov     eax, 120
        ret

In essence, outside of the specific case where you absolutely force compile time evaluation by assigning a constexpr function to another constexpr variable, compile time evaluation has more to do with the quality of your optimizer than the standard. 本质上,在通过将constexpr函数分配给另一个constexpr变量来绝对强制编译时评估的特定情况之外,编译时评估更多地与优化器的质量相关而不是标准。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM