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?
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.
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.
#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.
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.
No, there is no such way.
Sorry.
N3583 is a paper proposing changes to allow what you are asking for.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With