How to tell if `constexpr` is evaluated at compile time (without manual inspection)

被刻印的时光 ゝ 提交于 2020-03-16 08:57:20

问题


Is there a standard way to find out what the compiler does to constexpr functions?

(Side note: For debug, every constexpr function is deferred to runtime by default. Why is this sensible? Is there a way to influence this?)

For release it depends on the context. Obviously, for small test settings you can easily inspect the generated machine code, but this cannot be the way to go for a real project.

My current 'workaround' (VC++) is to break somewhere, go to my constexpr function and (try to) inspect the disassembly. If none is there, I conclude that it was all done at compile time. But it is not 100% reliable this way. (Optimization, etc.) Only the other way around is certain: If I do find disassembly (and can even break there), I know that it was NOT done at compile time.


回答1:


It's impossible. constexpr does not guarantee value inlining, you can see this manipulating optimization level here: https://godbolt.org/z/dAoiM-

Only since -O2 everything is inlined and the structure gets dissolved. Below that compiler happily uses runtime evaluation even for code used in constexpr context.

There are no standard language tools to inquire whether compiler applies particular optimization. It all boils down to the as-if rule. If the code behaves the same compiler can do anything to it. The only exception is mandatory RVO and other RVOs (they are allowed to changed observed behaviour.)

That being said. The constexpr is a useful hint. In the linked example if one removes constexpr specifiers even O3 (on recent clang and gcc) does not manage to remove the map.

It's worthwhile optimization-wise to write constexpr functions and data structure, making sure the compiler can optimize, though you cannot force it to.

You can force function to be evaluated in constexpr context, and you can also guard non-constexpr paths to throw, to prevent guaranteed run-time evaluation.

#include <iostream>
#include <vector>
using namespace std;

constexpr int f(int el) {
    return el > 0 ? el : throw "error";
}

int main() {
    // constexpr auto r = f(-1); // #1 compiler errors that throw is forbidden in  
                                 // constexpr, so it went into a non-constexpr path
                                 // and failed

    constexpr auto r = f(1);     // #2 fine - has to be interpreted in constexpr context
    cout << f(1) << '\n';        // #3 fine - can be interpreted in both contexts

    try {
        cout << f(-1) << '\n'; // # 4 // throws - i.e. runtime evaluation
    }
    catch (const char* e) {
        cout << e << '\n';
    }
    return 0;
}



回答2:


As we now have the current C++20 standard, we can use consteval.

From the docs:

consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant. doc

This will fix the problem with constexpr.



来源:https://stackoverflow.com/questions/52078752/how-to-tell-if-constexpr-is-evaluated-at-compile-time-without-manual-inspecti

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