Implementation considerations of library constexpr-ification

Document #: P4268R0
Date: 2026-07-15
Project: Programming Language C++
Audience: WG21
Reply-to: Louis Dionne
<>

1 Introduction

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.

2 Considerations

2.1 constexpr forces header-only implementations

A 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:

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.

2.2 constexpr implies inline

A 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.

2.3 constexpr reduces implementation freedom

A 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.

2.4 constexpr can slow down compilation in unexpected ways

When 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.

2.5 The specification cost is a poor proxy for implementation cost

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.

3 Conclusion

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.