In G++, various builtin math functions are constexpr under certain conditions. For example, the following compiles:
static constexpr double A = __builtin_sqrt(16.0);
static constexpr double B = __builtin_pow(A, 2.0);
They are not always constexpr though, it depends on the argument. For example, __builtin_sqrt(NAN)
results in a compile error when used as a constant expression.
But I'm hitting a strange case where it seems to me that it should be constexpr, but it is not:
static constexpr double value () { return 1.23; }
static constexpr double result = __builtin_round(__builtin_sqrt(value()));
This produces:
a.cpp:2:73: error: ‘__builtin_round(1.1090536506409416e+0)’ is not a constant expression
static constexpr double result = __builtin_round(__builtin_sqrt(value()));
^
I've tried variations of the above code, and I've found that:
__builtin_round
has some special role in the problem. Replacing it with some other builtin math function, such as sqrt
or pow
resolves the error. So would appear that __builtin_round
simply lacks constexpr support. But...value()
is replaced by a literal 1.23
, that too removes the error.__builtin_sqrt
, leaving only __builtin_round(value())
, removes the error too.I'd like to know why the round
is behaving in this way, and if there is any workaround.
NOTE. I am aware that the builtin math functions, with their constexpr-ness, are a non-standard compiler-specific feature. Please don't lecture me on how I should not be using this, or how I shouldn't be trying to do compile time math. In my case, having constexpr math is an important feature, and I'm fine with depending on G++.
A constant expression is an expression that contains only constants. A constant expression can be evaluated during compilation rather than at run time, and can be used in any place that a constant can occur.
A constant value is one that doesn't change. C++ provides two keywords to enable you to express the intent that an object is not intended to be modified, and to enforce that intent. C++ requires constant expressions — expressions that evaluate to a constant — for declarations of: Array bounds.
I have an idea of another workaround.
There is: use a helper function pass_through
template<typename T>
constexpr T&& pass_through (T&& t) { return static_cast<T&&>(t); }
use it like this:
static constexpr double value () { return 1.23; }
static constexpr double result = __builtin_round(pass_through(__builtin_sqrt(value())));
This code is compiled without error in the G++.
I also agree, the opinion that this issue should be reported to the GCC.
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