Constexpr Factorial Compilation Results in VS2015 and GCC 5.4.0

感情迁移 提交于 2021-02-10 05:58:45

问题


Wondering if the following surprises anyone, as it did me? Alex Allain's article here on using constexpr shows the following factorial example:

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.

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.

Using GCC v5.4.0 with --std=C++14, I must use /O2 or /O3 before the calculation is performed at compile time. I was surprised thought that using just /O the calculation did not occur at compilation time.

Main main question is: Why is VS2015 not performing this calculation at compilation time?


回答1:


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; 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).




回答2:


You have to use it in const expression, as:

 constexpr auto res = factorial(2);

else computation can be done at runtime.




回答3:


constexpr is neither necessary nor sufficient to compile time evaluation of a function.

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. 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.

The other point, is that the compiler is completely capable of evaluating things at compile time, even without 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.

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:

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.



来源:https://stackoverflow.com/questions/43741519/constexpr-factorial-compilation-results-in-vs2015-and-gcc-5-4-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!