如何判断在编译时是否评估了constexpr(无需手动检查)

时间:2018-08-29 13:34:48

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

有没有一种标准的方法来找出编译器对constexpr函数的作用?

(附带说明:对于调试,默认情况下,每个constexpr函数都推迟到运行时。为什么这样做很明智?有没有办法影响这一点?)

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

我当前的“解决方法”(VC ++)是要打断某个地方,转到我的constexpr函数,然后(尝试)检查反汇编。如果没有,我得出的结论是所有这些都是在编译时完成的。 但是这种方式并不是100%可靠的。 (优化等) 只能通过另一种方式确定:如果我发现反汇编(甚至可以在那里分解),我知道它不是在编译时完成的。

2 个答案:

答案 0 :(得分:1)

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

仅由于-O2,所有内容都被内联并且结构被溶解。在此之下,即使对于constexpr上下文中使用的代码,编译器也愉快地使用运行时评估。

没有标准的语言工具来询问编译器是否应用了特定的优化。归结为as-if rule。如果代码的行为相同,则编译器可以对其执行任何操作。唯一的例外是强制性RVO和其他RVO(允许它们更改观察到的行为。)

话虽如此。 constexpr是有用的提示。在链接的示例中,如果一个人删除了constexpr个说明符,即使O3(在最近的clang和gcc上)也无法删除地图。

编写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;
}

答案 1 :(得分:0)

现在我们有了当前的C ++ 20标准,因此可以使用consteval

从文档中

consteval-指定一个函数为立即函数,也就是说,每次对该函数的调用都必须产生一个编译时常量。 doc

这将解决constexpr的问题。