c++ - 如何判断 `constexpr`是否在编译时求值(无需人工检查)

标签 c++ c++11 compilation c++17 constexpr

是否有一种标准方法可以找出编译器对 constexpr 函数做了什么?

(旁注:对于调试,默认情况下每个 constexpr 函数都延迟到运行时。为什么这是明智的?有没有办法影响它?)

对于发布,它取决于上下文。显然,对于小型测试设置,您可以轻松检查生成的机器代码,但这不是实际项目的方法。

我当前的“解决方法”(VC++) 是在某处中断,转到我的 constexpr 函数并(尝试)检查反汇编。如果没有,我的结论是这一切都是在编译时完成的。 但这种方式并不是 100% 可靠的。 (优化等) 只有另一种方式是肯定的:如果我确实找到反汇编(甚至可以在那里中断),我知道它不是在编译时完成的。

最佳答案

这是不可能的。 constexpr 不保证值内联,你可以在这里看到这个操纵优化级别:https://godbolt.org/z/dAoiM-

只有从 -O2 开始,一切都被内联并且结构被分解。在该编译器之下,即使对于 constexpr 上下文中使用的代码,编译器也会愉快地使用运行时评估。

没有标准的语言工具可以查询编译器是否应用了特定的优化。这一切都归结为 as-if rule .如果代码的行为相同,编译器可以对它做任何事情。唯一的异常(exception)是强制性 RVO 和其他 RVO(允许它们改变观察到的行为。)

话虽这么说。 constexpr 是一个有用的提示。在链接示例中,如果删除 constexpr 说明符,甚至 O3(在最近的 clang 和 gcc 上)也无法删除 map 。

编写 constexpr 函数和数据结构是值得优化的,确保编译器可以优化,尽管你不能强制它。

您可以强制在 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;
}

关于c++ - 如何判断 `constexpr`是否在编译时求值(无需人工检查),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52078752/

相关文章:

c++ - 使用 GLFW 在 MacOS 上设置 OpenGL 3.2+

c++ - 曲面 segmentation 的理论与算法

c++ - std::async 导致死锁?

c++ - 为什么下面的多线程代码会导致 SIGABRT ?

c++ - 如何正确地将转换构造函数从 std::queue 传递到底层 std::deque?

windows - Tasm 对名称较长的文件给出错误

c++ - Robai Cyton Joint Velocity 使用 Actions API

c++ - 将 const wchar_t* 和 cont char* 从 VB 传递到 C++ DLL

java - 如何在java中以单个命令编译和运行

c - 尝试编译轻木时出现未知类型名称 ‘gpgme_decrypt_result_t’