简体   繁体   English

如果忽略结果,则不会在编译时调用 Consexpr 函数

[英]Constexpr functions not called at compile-time if result is ignored

I was investigating some rather weird code-coverage results of constexpr functions (compile-time calls can't get instrumented by the code-coverage tool I use), and noticed that some constexpr functions were getting called as runtime functions, if the results of the function call were not stored .我正在调查constexpr函数的一些相当奇怪的代码覆盖结果(我使用的代码覆盖工具无法检测编译时调用),并注意到一些constexpr函数被调用为运行时函数,如果结果function 调用未存储

It seems that, for constexpr functions or methods, if you store the results of the call (either in a runtime variable [emphasis!!!] or a constexpr variable), the call is a compile-time call (as long as the parameters are compile-time).看来,对于constexpr函数或方法,如果存储调用的结果(在运行时变量 [emphasis!!!] 或constexpr变量中),则调用是编译时调用(只要参数是编译时)。 If you ignore the results, the call is a runtime call.如果忽略结果,则调用是运行时调用。 This has nothing to do with my code-coverage tool;这与我的代码覆盖工具无关; the behavior seems to be repeatable in the simple example below.在下面的简单示例中,该行为似乎是可重复的。

You could argue that since constexpr functions cannot have side-effects, it doesn't matter what the compiler does if you don't return / use a result.您可能会争辩说,由于constexpr函数不会有副作用,因此如果您不返回/使用结果,编译器会做什么并不重要。 I'd think that for efficiency, the compiler would still make whatever it can be constexpr , but that's neither here nor there... What I'm wondering is if this is even defined behavior.我认为为了提高效率,编译器仍然会做任何它可以是constexpr的东西,但这既不在这里也不在那里......我想知道这是否甚至是定义的行为。

Is this a portable way to guarantee your constexpr functions will be invoked as runtime???这是保证您的constexpr函数将作为运行时调用的可移植方式吗??? There aren't a ton of uses for that, but one use is: if you want to "take credit for tests that were called on constexpr functions" in code coverage, by just calling the same function at the end of your unit test, and ignoring the result, so that they get instrumented.没有很多用途,但一个用途是:如果您想在代码覆盖率中“为在constexpr函数上调用的测试赢得荣誉”,只需在单元测试结束时调用相同的 function,并忽略结果,以便他们得到检测。

There are other ways to force a function to get called as runtime, I know, I'm mostly curious about what's going on here.还有其他方法可以强制 function 被称为运行时,我知道,我主要对这里发生的事情感到好奇。 It was very unexpected when I first saw it.当我第一次看到它时,这是非常出乎意料的。 Unless this is portable, I'll probably just call my constexpr methods through a runtime object (which seems to do the trick even for static methods), or through a runtime function pointer.除非这是可移植的,否则我可能只是通过运行时 object 调用我的constexpr方法(即使对于 static 方法似乎也能做到这一点),或者通过运行时 ZC1C425268E68385D1AB5074C17A9F4 指针。

See example below.请参见下面的示例。 Live demo: https://onlinegdb.com/rJao0RNGP现场演示: https://onlinegdb.com/rJao0RNGP

// Modified from https://stackoverflow.com/a/40410624/12854372

extern bool no_symbol;

struct ContextIsConstexpr {
    size_t s;

    constexpr ContextIsConstexpr() : s(1) {}
    
    constexpr void operator()() {
        auto ignore = s ? 1 : no_symbol;
    }
};

constexpr bool tryIgnoringResult()
{
    ContextIsConstexpr()();
    return true;
}

constexpr void thereIsNoResult() {
    ContextIsConstexpr()();
}

int main()
{
    constexpr auto result1 = tryIgnoringResult(); // OK, compile-time
    auto result2 = tryIgnoringResult(); // OK, compile-time

    // tryIgnoringResult(); // Unexpected, runtime!
    // thereIsNoResult(); // Unexpected, runtime!
}

It might be confusing, but constexpr functions should be called at compile time only in constexpr contexts (assignation to constexpr variable, use for array size or template parameter, ...).这可能会令人困惑,但 constexpr 函数应该在编译时仅在 constexpr 上下文中调用(分配给 constexpr 变量,用于数组大小或模板参数,...)。

In regular context, functions are called at runtime.在常规上下文中,函数在运行时被调用。 Optimizer might resolve that function at compile time (as for any other functions following the as-if rule).优化器可能会在编译时解析 function(对于任何其他遵循 as-if 规则的函数)。 constexpr is indeed a good hint for optimization to happen. constexpr确实是优化发生的一个很好的提示。

You could argue that since constexpr functions cannot have side-effects你可以争辩说,因为 constexpr 函数不能有副作用

They can have side effect, see following valid example:它们可能有副作用,请参见以下有效示例:

constexpr int f(int i)
{
    if (i == 0) return 0;
    std::cout << i << std::endl;
    return i;
}

int main()
{
    [[maybe_unused]] constexpr int zero = f(0); // Compile time
    f(42); // runtime
}

Demo演示

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

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