cout is able to run at compile-time

94 views Asked by At

I think cout is only allowed to run at runtime but the following code proves otherwise. Or am I not understanding something deeper? I only expected it to print the message once, but it printed twice. Why is that?

import std;

constexpr void logError(const std::string& error);

constexpr int sqrt(int x)
{
    if (x < 0)
    {
        logError("Oh no, this can't be real...");
        return -1;
    }
    else
    {
        int result{ 1 };
        while (result * result <= x) ++result;
        return result - 1;
    }
}

int c = sqrt(-1);

int main()
{
    sqrt(-1);
   
}

constexpr void logError(const std::string& error)
{
    if (!std::is_constant_evaluated())
        std::cout << error << std::endl;
}

I think this code int c = sqrt(-1); calls logError, but it is not allowed, isn't it?

1

There are 1 answers

10
Jan Schultke On

I think cout is only allowed to run at runtime but the following code proves otherwise. Or am I not understanding something deeper?

You're right about std::cout. You just misunderstand how constexpr relates to compile-time evaluation.

constexpr doesn't mean that logError is run at compile-time. It merely means that the function can possibly run at compile-time, if needed.

int c = sqrt(-1);

... is not a case where a constant expression is required to initialize c, so sqrt(-1) as run at run-time. See also When does a constexpr function get evaluated at compile time?

Furthermore, it would be safe to run logError at compile-time because the check for std::is_constant_evaluated() ensures that std::cout << isn't done within a constant expression. See C++20 constexpr std::copy optimizations for run-time for an example of how it's typically used.

Further notes

It's not a good idea to split constexpr functions into declaration and definition like you've done. A constexpr function can only be used within a a constant expression once it's been defined. See also Use of constexpr function before definition fails