I was reading about constexpr
here:
The
constexpr
specifier declares that it is possible to evaluate the value of the function or variable at compile time.
When I first read this sentence, it made perfect sense to me. However, recently I've come across some code that completely threw me off. I've reconstructed a simple example below:
#include <iostream>
void MysteryFunction(int *p);
constexpr int PlusOne(int input) {
return input + 1;
}
int main() {
int i = 0;
MysteryFunction(&i);
std::cout << PlusOne(i) << std::endl;
return 0;
}
Looking at this code, there is no way for me to say what the result of PlusOne(i)
should be, however it actually compiles! (Of course linking will fail, but g++ -std=c++11 -c
succeeds without error.)
What would be the correct interpretation of "possible to evaluate the value of the function 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.
constexpr specifies that the value of an object or a function can be evaluated at compile-time and the expression can be used in other constant expressions.
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
#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.
A constexpr
function may be called within a constant expression, provided that the other requirements for the evaluation of the constant expression are met. It may also be called within an expression that is not a constant expression, in which case it behaves the same as if it had not been declared with constexpr
. As the code in your question demonstrates, the result of calling a constexpr
function is not automatically a constant expression.
The quoted wording is a little misleading in a sense. If you just take PlusOne
in isolation, and observe its logic, and assume that the inputs are known at compile-time, then the calculations therein can also be performed at compile-time. Slapping the constexpr
keyword on it ensures that we maintain this lovely state and everything's fine.
But if the input isn't known at compile-time then it's still just a normal function and will be called at runtime.
So the constexpr
is a property of the function ("possible to evaluate at compile time" for some input, not for all input) not of your function/input combination in this specific case (so not for this particular input either).
It's a bit like how a function could take a const int&
but that doesn't mean the original object had to be const
. Here, similarly, constexpr
adds constraints onto the function, without adding constraints onto the function's input.
Admittedly it's all a giant, confusing, nebulous mess (C++! Yay!). Just remember, your code describes the meaning of a program! It's not a direct recipe for machine instructions at different phases of compilation.
(To really enforce this you'd have the integer be a template argument.)
What would be the correct interpretation of "possible to evaluate the value of the function at compile time"?
If all the arguments to the function are evaluatable at compile time, then the return value of the function can be evaluated at compile time.
However, if the values of the arguments to the function are known only at run time, then the retun value of the function can only be evaluated at run time.
Hence, it possible to evaluate the value of the function at compile time but it is not a requirement.
All the answers are correct, but I want to give one short example that I use to explain how ridiculously unintuitive constexpr is.
#include <cstdlib>
constexpr int fun(int i){
if (i==42){
return 47;
} else {
return rand();
}
}
int main()
{
int arr[fun(42)];
}
As a side note: some people find constexpr status unsatisfying so they proposed constexpr! keyword addition to the language.
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