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?
82 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.
2