consteval
variables| Document #: | P4339R0 [Latest] [Status] |
| Date: | 2026-08-04 |
| Project: | Programming Language C++ |
| Audience: |
EWG |
| Reply-to: |
Barry Revzin <barry.revzin@gmail.com> Peter Dimov <pdimov@gmail.com> |
[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.
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.
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.
This has been implemented in Barry’s fork of Clang since Sofia. You can see it on compiler explorer.
[ 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
constevalspecifiers 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.TheA function or static data member declared with theconstevalspecifier shall be applied only to the declaration of a function or function template.constexprorconstevalspecifier on its first declaration is implicitly an inline function or variable ([dcl.inline]). If any declaration of a function or function template has aconstexprorconstevalspecifier, then all its declarations shall contain the same specifier.[ Note: An explicit specialization can differ from the template declaration with respect to the
constexprorconstevalspecifier. — end note ][ Note: Function parameters cannot be declared
constexprorconsteval. — end note ][…]
6 A
constexprorconstevalspecifier used in an object declaration declares the object asconst. Such an object shall have literal type and shall be initialized. Aconstexprorconstevalspecifier used in the declaration of a variable declares that variable to be a constexpr variable. Aconstexpr variable shall be constant-initializable ([expr.const.init]). Aconstexprconstexpr variable that is an object, as well as any temporary to which aconstexprconstexpr reference is bound, shall have constant destruction.constexpr
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
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 ofD, including that of any structured-binding-declaration ofD, shall be either a type-specifier,consteval, orconstexpr.
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-SPECIFIERconsist of each decl-specifier of the decl-specifier-seq of the for-range-declaration that is eitherconstevalorconstexpr.[…]
(5.2) Otherwise, if
Sis an iterating expansion statement,Sis equivalent to:{ init-statementconstexproptCONST-SPECIFIER decltype(auto) range = ( expansion-initializer );constexproptCONST-SPECIFIER auto begin = begin-expr; // see [stmt.ranged] S0 ... S-1 }where
Nis the result of evaluating the expression[…]
and
Siis{constexproptCONST-SPECIFIER auto iter = begin + decltype(begin - begin){i}; for-range-declaration = *iter; compound-statement }The variables
range,begin, anditerare 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 identifieriis considered to be a prvalue of typestd::ptrdiff_t; the program is ill-formed ifiis not representable as such a value.(5.3) Otherwise,
Sis a destructuring expansion statement and, ifNis0,Sis equivalent to:{ init-statementconstexproptCONST-SPECIFIER auto&& range = expansion-initializer; }otherwise,
Sis equivalent to:{ init-statementconstexproptCONST-SPECIFIER auto&& [u0, u1, ..., u-1] = expansion-initializer ; S0 ... SN-1 }where
Nis the structured binding size of the type of theexpansion-initializerandSiis{ for-range-declaration = vi ; compound-statement }If the expansion-initializer is an lvalue, then
viisui; otherwise,viisstatic_cast<decltype(ui)&&>(ui).The keywordconstexpris present in the declaration ofu0, u1, ..., u-1if and only ifconstexpris one of thedecl-specifiers of thedecl-specifier-seqof thefor-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
constexprorconstevalspecifier, 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
Sconsist of each decl-specifier of the decl-specifier-seq that isconstexpr,consteval,constinit, or a storage-class-specifier. […]
Bump the value of __cpp_consteval
in 15.12 Predefined macro names [cpp.predefined].