简体   繁体   English

如何判断 `constexpr` 是否在编译时被评估(无需人工检查)

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

Is there a standard way to find out what the compiler does to constexpr functions?有没有标准的方法来找出编译器对constexpr函数做了什么?

(Side note: For debug, every constexpr function is deferred to runtime by default. Why is this sensible? Is there a way to influence this?) (旁注:对于调试,默认情况下每个 constexpr 函数都推迟到运行时。为什么这是明智的?有没有办法影响这一点?)

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.我当前的“解决方法”(VC++)是在某个地方中断,转到我的 constexpr 函数并(尝试)检查反汇编。 If none is there, I conclude that it was all done at compile time.如果没有,我得出结论,这一切都是在编译时完成的。 But it is not 100% reliable this way.但这种方式并非 100% 可靠。 (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. (优化等)只有相反的方式是确定的:如果我确实找到了反汇编(甚至可以在那里中断),我知道它不是在编译时完成的。

It's impossible.不可能。 constexpr does not guarantee value inlining, you can see this manipulating optimization level here: https://godbolt.org/z/dAoiM- constexpr不保证值内联,你可以在这里看到这个操纵优化级别: https : //godbolt.org/z/dAoiM-

Only since -O2 everything is inlined and the structure gets dissolved.只有因为 -O2 一切都被内联并且结构被溶解。 Below that compiler happily uses runtime evaluation even for code used in constexpr context.在该编译器之下,即使对于在constexpr上下文中使用的代码,也很乐意使用运行时评估。

There are no standard language tools to inquire whether compiler applies particular optimization.没有标准的语言工具来查询编译器是否应用了特定的优化。 It all boils down to the as-if rule .这一切都归结为as-if 规则 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.)唯一的例外是强制性 RVO 和其他 RVO(允许他们改变观察到的行为。)

That being said.话虽如此。 The constexpr is a useful hint. constexpr是一个有用的提示。 In the linked example if one removes constexpr specifiers even O3 (on recent clang and gcc) does not manage to remove the map.在链接的示例中,如果删除了constexpr说明符,即使O3 (在最近的 clang 和 gcc 上)也无法删除地图。

It's worthwhile optimization-wise to write constexpr functions and data structure, making sure the compiler can optimize, though you cannot force it to.编写constexpr函数和数据结构是值得优化的,确保编译器可以优化,尽管你不能强迫它。

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.您可以强制在constexpr上下文中评估函数,也可以保护要抛出的非 constexpr 路径,以防止有保证的运行时评估。

#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;
}

As we now have the current C++20 standard, we can use consteval .由于我们现在拥有当前的 C++20 标准,我们可以使用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. consteval - 指定一个函数是一个立即函数,也就是说,对函数的每次调用都必须产生一个编译时常量。 doc文档

This will fix the problem with constexpr .这将解决constexpr的问题。

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

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