Consider this example:
This function is totally fine. But when we try to extend it to work at compile time too, we run into a problem:
This is ill-formed. And it’s ill-formed for no good reason. We should make it valid.
static variables could be declared in
constexpr functions at all. That was relaxed in [P2242R3], which restructured the wording to be based on the actual control flow: rather than the function body not being allowed to contain a
static variable declaration, now the rule is that control flow needs to not pass through an initialization of a
This makes sense for the perspective of a
static (or, worse,
thread_local) variable, whose initializer could run arbitrary code. But for a
static constexpr variable, which must, by definition, be constant-initialization, there’s no question about whether and when to run what initialization. It’s a constant.
There are several workarounds for getting the above example to work. We could eschew the
static variable entirely and directly index the literal, but this only works if we need to use it exactly one time:
We could move the
static variable into non-local scope, though we wanted to make it local for a reason - it’s only relevant to this particular function:
Or we could wrap the variable into a
consteval lambda, which is the most general workaround for this problem, whose only downside is that… we’re writing a
consteval lambda because we can’t write a variable:
Having a local
static constexpr variable is simply the obvious, most direct solution to the problem. We should permit it.
Change 7.7 [expr.const]/5.2:
5 An expression
Eis a core constant expression unless the evaluation of
E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
[P2242R3] Ville Voutilainen. 2021-07-13. Non-literal variables (and labels and gotos) in constexpr functions.