Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine `constexpr` execution - during compilation or at runtime?

Is there a way to achieve different behaviour of a constexpr function in the compilation phase and at runtime?

Consider the following example (using a theoretical feature from D: static if):

constexpr int pow( int base , int exp ) noexcept
{
    static if( std::evaluated_during_translation() ) {
        auto result = 1;
        for( int i = 0 ; i < exp ; i++ )
            result *= base;
        return result;
    } else { // std::evaluated_during_runtime()
        return std::pow( base , exp );
    }
}

If not, is there a way to restrict constexpr to be compile-time only?

like image 388
nonsensation Avatar asked Feb 23 '15 20:02

nonsensation


People also ask

Is constexpr evaluated at compile time?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

When to use #define vs constexpr?

#define (also called a 'macro') is simply a text substitution that happens during preprocessor phase, before the actual compiler. And it is obviously not typed. constexpr on the other hand, happens during actual parsing. And it is indeed typed.

Where is constexpr defined?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value.


2 Answers

No, there is no such way.

Sorry.

N3583 is a paper proposing changes to allow what you are asking for.

like image 133
Yakk - Adam Nevraumont Avatar answered Oct 18 '22 20:10

Yakk - Adam Nevraumont


Prior to C++20, this wasn't possible. C++20 then added std::is_constant_evaluated which is exactly for this use case:

constexpr int pow(int base, int exp) noexcept
{
    if (std::is_constant_evaluated())
    {
        auto result = 1;

        for (int i = 0; i < exp; i++)
            result *= base;

        return result;
    } 
    else
    {
        return std::pow(base, exp);
    }
}

Note that the if statement itself is not constexpr. If it were, the whole else arm would be removed from the function and it would always run the if arm, no matter if at compile time or runtime. With a normal if statement, you basically get two functions. One that runs at compile time:

constexpr int pow(int base, int exp) noexcept
{
    auto result = 1;

    for (int i = 0; i < exp; i++)
        result *= base;

    return result;
}

and one that gets compiled an runs at runtime:

constexpr int pow(int base, int exp) noexcept
{
    return std::pow(base, exp);
}

The compiler can safely remove the if arm because it can prove that it isn't reachable at runtime. Pretty neat.

like image 4
Timo Avatar answered Oct 18 '22 22:10

Timo