The Value of a Const Variable Is or Is Not Usable in a Constant Expression, Depending on the Variable Type
The Following Code Is Fine: Constexpr Double Square_Cstxpr(Double X) { Return X * X; } Int Main() { Const Int Test = 5; Constexpr Double Result =...
The following code is fine:
constexpr double square_cstxpr(double x) { return x * x; }
int main() {
const int test = 5;
constexpr double result = square_cstxpr((double)test);
}
However, if the type of test is changed from const int to const double, g++ gives the following error: the value of 'test' is not usable in a constant expression.
See the code and output of g++ here:
Could somebody explain that behavior?
2 Answers
From constant expression (Core constant expressions):
10) Any other lvalue-to-rvalue implicit conversion, unless the lvalue...
a) has integral or enumeration type and refers to a complete non-volatile const object, which is initialized with a constant expression
It means, that here:
const int test1 = 5;
constexpr double result1 = square_cstxpr((double)test1);
test1 is a constant expression, square_cstxpr can be called with test1 as an argument at compile time and its result can be assigned to constexpr variable result.
On the other hand, here:
const double test2 = 5;
constexpr double result2 = square_cstxpr((double)test2);
test2 is not a constant expression because it is not of integral or enumeration type. Consequently, square_cstxpr cannot be called at compile time with test2as an argument.
Non-constexpr but const variables must be of integer or enumeration type for them to be usable in constant expressions. See [expr.const]/2:
an lvalue-to-rvalue conversion unless it is applied to
(2.7.1) a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or [..]
The reasons for this limitation must be mostly historical. Floating points have been handled with care when it comes to constant expressions; think non-type template parameters. This is due to their strongly platform dependent behaviour that renders compile time calculations less mathematical than they should be.