| Document #: | P4268R0 |
| Date: | 2026-07-15 |
| Project: | Programming Language C++ |
| Audience: |
WG21 |
| Reply-to: |
Louis Dionne <ldionne.2@gmail.com> |
A wave of recent proposals targets parts of the standard library for
constexpr-ification.
Some of them have already been adopted in C++26, others are being
considered for C++29. These papers are often perceived as
straightforward, since they are only sprinkling
constexpr
around the standard library. However, in practice, these papers may
involve subtle tradeofs for standard libraries and their users, and
non-trivial implementation efforts for maintainers.
This paper does not argue against
constexpr-ifying
the library. It surfaces some implementation concerns that have come up
across multiple proposals, with the goal of helping the committee make
informed decisions. Also note that this paper is probably not exhaustive
– this list is only what the author could think about on the spot.
constexpr
forces header-only implementationsA
constexpr
function must be defined in the headers because its body must be visible
by the compiler. Normally, implementations carefully decide where each
function and class is defined:
<string>
everywhere, which led to a 50% increase in the size of <vector>
in libstdc++ according to its maintainers. Other implementations should
have a similar fate.Also, relocating a definition previously defined in the shared library without breaking ABI is feasible but non-trivial (involves e.g. symbol aliases), and carries a long term maintenance cost.
constexpr
implies
inlineA
constexpr
function is implicitly
inline. Even
though this is not required, in practice this causes compilers to more
aggressively inline these functions (even when they were previously
defined in headers). This has an effect on binary size, runtime
performance, and debugging experience. This happens even when no caller
ever runs the function during constant evaluation.
constexpr
reduces implementation freedomA
constexpr
API can no longer rely on operations forbidden during constant
evaluation: reinterpret_cast,
type punning, many builtins, hand-written assembly, SIMD intrinsics, and
so on. These are often used to provide:
Some of these can be worked around with if consteval
branches, but some can’t. In particular,
constexpr-ification
can force opening the body of a function that was previously defaulted
(to add compile-time handling or to deal with representational changes
required by
constexpr),
which has an impact on the triviality of the function and the generation
of special member functions, amongst other things. Furthermore, if consteval
effectively means duplicated implementations, which also increases the
maintenance and testing burden and the likelihood of bugs.
Finally, the same constraints apply to tests themselves. Standard
library tests often rely on techniques that are not
constexpr-friendly,
for example using global state to count how many times a function is
called. Refactoring tests to be
constexpr-friendly
is often non-trivial, and sometimes the
constexpr
version can’t be fully tested.
constexpr
can slow down compilation in unexpected waysWhen the compiler performs trial constant evaluation
(e.g. initialization of global variables), it instantiates any constexpr
function encountered, which can have suprising consequences. For
example, this defeats attempts to reduce compilation times with explicit
template instantiations, which was observed to cause a noticeable
compilation-time regression in libstdc++’s
std::format
according to its maintainers, even to pre-existing code that did not
intend to use
std::format
in
constexpr.
Constexpr <cmath>
is a good example. The specification was essentially “add
constexpr to
these declarations”. The implementation for LLVM is still ongoing after
more than one year of active work by someone with deep expertise in
these math functions. The effort requires LLVM libc to modify all of its
math functions so they can be reused by Clang directly to implement new
math builtins that will then be used by libc++ under if consteval.
Other
constexpr
proposals have shown similar gaps between specification simplicity and
implementation reality.
The goal of this paper is not to argue against
constexpr in
the library. However, we want to push back on the idea that these
proposals are inherently small or trivial. Their wording is often
simple, but they often carry a heavy weight in implementation cost, lost
implementation freedom, and quality of implementation. This cost is not
only paid by maintainers, but also by users. There is also a clear
prioritization question:
constexpr-ification
efforts take time from implementers who could otherwise work on
improving other parts of the library.
This paper also shows that claims that “an implementation exists”
should not always be taken at face value by the design groups.
Experimental implementations which consist of adding
constexpr to
the declarations in an existing library and checking common use cases
manually are not sufficient to confirm real implementability, and are
not a good proxy to measure true implementation cost.
We hope this paper helps the committee make informed design and prioritization decisions.