consteval variables

Document #: P4339R0 [Latest] [Status]
Date: 2026-08-04
Project: Programming Language C++
Audience: EWG
Reply-to: Barry Revzin
<>
Peter Dimov
<>

1 Proposal

[P4101R1] (Consteval-only Values for C++26) introduced support for implicit consteval variables — variables that only exist during compile-time in a way that is enforced by the language.

This paper proposes support for explicit consteval variables. This is valuable simply for visibility. But another important benefit of consteval variables is that they are guaranteed to not occupy space at runtime. You just don’t hit issues like this. constexpr variables, even if never accessed at runtime, may occupy space anyway. It’s just QoI. But in the same way that consteval functions cannot lead to codegen, consteval variables cannot either. That’s a pretty nice benefit.

With [P4101R1], this is a very small change, since the notion of consteval variable already exists — and implementations already have to track this to properly enforce the rules. So this proposal is a small amount of implementation (mostly just allowing consteval on variable declarations) and wording.

1.1 Mutability

We propose that a variable declared consteval is similar to a variable declared constexpr — it is implicitly const. When we tackle compile-time mutable state, we believe that those variables should be declared consteval mutable instead.

1.2 Allocation

This proposal also doesn’t provide any enhancements to the kinds of things we could do with consteval variables. As mentioned in both [P3603R1] and [P4101R1], a consteval variable could be allowed to “persist” its allocation. It’s a compile-time only variable, so none of the issues around non-transient allocation exist. But that will come in a future paper.

1.3 Implementation Experience

This has been implemented in Barry’s fork of Clang since Sofia. You can see it on compiler explorer.

2 Wording

[ Drafting note: We’re defining the term “constexpr variable” to be those variables declared either constexpr or consteval, since all rules we have apply to both (except for a new one specifically for those declared consteval). This is simpler than making sure we catch all the uses of “constexpr” to be “constexpr or consteval”, and is how Barry implemented it too. ]

Allow variables to be declared consteval in 9.2.6 The constexpr and consteval specifiers [dcl.constexpr]:

1 The constexpr and consteval specifiers shall be applied only to the definition of a variable or variable template, a structured binding declaration, or the declaration of a function or function template. The consteval specifier shall be applied only to the declaration of a function or function template. A function or static data member declared with the constexpr or consteval specifier on its first declaration is implicitly an inline function or variable ([dcl.inline]). If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.

[ Note:  An explicit specialization can differ from the template declaration with respect to the constexpr or consteval specifier.end note ]

[ Note: Function parameters cannot be declared constexpr or consteval.end note ]

[…]

6 A constexpr or consteval specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. A constexpr or consteval specifier used in the declaration of a variable declares that variable to be a constexpr variable. A constexpr constexpr variable shall be constant-initializable ([expr.const.init]). A constexpr constexpr variable that is an object, as well as any temporary to which a constexpr constexpr reference is bound, shall have constant destruction.

Extend the definition of immediate object to include those declared by consteval variables in 7.7.3 Constant expressions [expr.const.const]:

2 An object is an immediate object if its complete object has

  • (2.0) is the object declared by, or a temporary object whose lifetime is extended to that of, a variable declared with the consteval specifier,
  • (2.1) has a constituent value that is consteval-only, or
  • (2.2) has a constituent reference that refers to an immediate object or immediate function.

Add consteval to what you can do in an expansion statement and if/for/while condition, first in 8.1 Preamble [stmt.pre]:

8 For any condition or for-range-declaration D, each decl-specifier in the decl-specifier-seq of D, including that of any structured-binding-declaration of D, shall be either a type-specifier, consteval, or constexpr.

And in 8.7 Expansion statements [stmt.expand], mirroring the wording in 9.7 Structured binding declarations [dcl.struct.bind]:

1 Expansion statements specify repeated instantiations ([temp.decls.general]) of their substatement.

Let CONST-SPECIFIER consist of each decl-specifier of the decl-specifier-seq of the for-range-declaration that is either consteval or constexpr.

[…]

  • (5.2) Otherwise, if S is an iterating expansion statement, S is equivalent to:

    {
      init-statement
      constexpropt CONST-SPECIFIER decltype(auto) range = ( expansion-initializer );
      constexpropt CONST-SPECIFIER auto begin = begin-expr; // see [stmt.ranged]
    
      S0
      ...
      SNN-1
    }

    where N is the result of evaluating the expression

    […]

    and Si is

    {
      constexpropt CONST-SPECIFIER auto iter = begin + decltype(begin - begin){i};
      for-range-declaration = *iter;
      compound-statement
    }

    The variables range, begin, and iter are defined for exposition only. The keyword constexpr is present in the declarations of range, begin, and iter if and only if constexpr is one of the decl-specifiers of the decl-specifier-seq of the for-range-declaration. The identifier i is considered to be a prvalue of type std​::​ptrdiff_t; the program is ill-formed if i is not representable as such a value.

  • (5.3) Otherwise, S is a destructuring expansion statement and, if N is 0, S is equivalent to:

    {
      init-statement
      constexpropt CONST-SPECIFIER auto&& range = expansion-initializer;
    }

    otherwise, S is equivalent to:

    {
      init-statement
      constexpropt CONST-SPECIFIER auto&& [u0, u1, ..., uNN-1] = expansion-initializer ;
      S0
      ...
      SN-1
    }

    where N is the structured binding size of the type of the expansion-initializer and Si is

    {
      for-range-declaration = vi ;
      compound-statement
    }

    If the expansion-initializer is an lvalue, then vi is ui; otherwise, vi is static_cast<decltype(ui)&&>(ui). The keyword constexpr is present in the declaration of u0, u1, ..., uNN-1 if and only if constexpr is one of the decl-specifiers of the decl-specifier-seq of the for-range-declaration.

Add consteval to the list of structured bindings declarations in 9.1 Preamble [dcl.pre]:

7 A simple-declaration or a condition with a structured-binding-declaration is called a structured binding declaration ([dcl.struct.bind]). Each decl-specifier in the decl-specifier-seq shall be consteval, constexpr, constinit, static, thread_local, auto ([dcl.spec.auto]), or a cv-qualifier. The declaration shall contain at most one sb-identifier whose identifier is preceded by an ellipsis. If the declaration contains any such sb-identifier, it shall declare a templated entity ([temp.pre]).

Adjust 9.5.1 General [dcl.init.general]:

2 Except for objects declared with the constexpr or consteval specifier, for which see [dcl.constexpr], […]

Update consteval handling in 9.7 Structured binding declarations [dcl.struct.bind]:

1 […] Let cv denote the cv-qualifiers in the decl-specifier-seq and S consist of each decl-specifier of the decl-specifier-seq that is constexpr, consteval, constinit, or a storage-class-specifier. […]

2.1 Feature-test Macro

Bump the value of __cpp_consteval in 15.12 Predefined macro names [cpp.predefined].

3 References

[P3603R1] Barry Revzin, Peter Dimov. 2025-10-06. Consteval-only Values and Consteval Variables.
https://wg21.link/p3603r1
[P4101R1] Barry Revzin, Peter Dimov, Daveed Vandevoorde, Dan Katz. 2026-06-12. Consteval-only Values for C++26.
https://wg21.link/p4101r1