In reference to this question. The core constant expression that is used to initialize the constexpr
variable y
is ill-formed. So much is a given.
But if I try to turn the if
into an if constexpr
:
template <typename T> void foo() { constexpr int x = -1; if constexpr (x >= 0){ constexpr int y = 1 << x; } } int main(){ foo<int>(); }
The error persists. With GCC 7.2 still giving:
error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]
But I thought that the semantic check should be left unpreformed on a discarded branch.
Making an indirection via a constexpr
lambda does help, however:
template <typename T> void foo(){ constexpr int x = -1; constexpr auto p = []() constexpr { return x; }; if constexpr (x >= 0){ constexpr int y = 1<<p(); } }
The constexpr
specifier on y
seems to alter how the discarded branch is checked. Is this the intended behavior?
@max66 was kind enough to check other implementations. He reports that the error is reproducible with both GCC (7.2.0 / Head 8.0.0) and Clang (5.0.0 / Head 6.0.0).
Short answer: static_assert(false) should never appear in a constexpr if expression, regardless of whether it's in a template function or whether it's in the discarded branch.
This is a big one! The static-if for C++! The feature allows you to discard branches of an if statement at compile-time based on a constant expression condition.
A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations. And when a value is computed at compile time instead of run time, it helps your program run faster and use less memory.
Constant expression. A constant expression is either. a glvalue core constant expression that refers to. an object with static storage duration that is not a temporary, or. an object with static storage duration that is a temporary, but whose value satisfies the constraints for prvalues below, or.
a constexpr function can only invoke other functions marked constexpr , and every expression involved (this includes creating objects) must be such that can appear in a constant-expression, and;
Constant expression. Literal constant expression is a prvalue core constant expression of non-pointer literal type (after conversions as required by context). A literal constant expression of array or class type requires that each subobject is initialized with a constant expression.
A literal constant expression of array or class type requires that each subobject is initialized with a constant expression. Reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function.
The standard doesn't say much about the discarded statement of an if constexpr
. There are essentially two statements in [stmt.if] about these:
Neither of these applies to your use: the compilers are correct to complain about the constexpr
if initialisation. Note that you'll need to make the condition dependent on a template parameter when you want to take advantage of the instantiation to fail: if the value isn't dependent on a template parameter the failure happens when the template is defined. For example, this code still fails:
template <typename T> void f() { constexpr int x = -1; if constexpr (x >= 0){ constexpr int y = 1<<x; } }
However, if you make x
dependent on the type T
it is OK, even when f
is instantiated with int
:
template <typename T> void f() { constexpr T x = -1; if constexpr (x >= 0){ constexpr int y = 1<<x; } } int main() { f<int>(); }
Note that for the statement discarded by Constexpr If:
the discarded statement can't be ill-formed for every possible specialization:
To fix the issue you can make the statement depending on the template parameter, e.g.
template<typename T, int X> struct dependent_value { constexpr static int V = X; }; template <typename T> void foo() { constexpr int x = -1; if constexpr (x >= 0){ constexpr int y = 1 << dependent_value<T, x>::V; } }
LIVE
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