1. Proposal
I propose to make the
and
functions for floating-point types usable in constant expressions.
2. Motivation
[P2291R3] added
to the integer overloads of
and
.
The floating-point overloads were left out of consideration, as at the time there was little implementation experience even without
.
Quoting [P2291R3] (1.2.2 Floating point):
/
std :: from_chars are probably the most difficult to implement parts of a standard library. As of January 2021, only one of the three major implementations has full support of [P0067R5]:
std :: to_chars
Since then, standard libraries implemented the floating-point overloads of
and
.
Popular 3rd party implementations of these functions also made their implementations
.
In addition to the original motivation in [P2291R3], the utility of having all of the
functions available during constant evaluation is also greatly increased in combination with [P1967R14] (#embed), [P2741R3] (user-generated
messages) and [P2758R4] (emitting messages at compile time).
3. Implementation experience
I contributed to the [fast_float] and [dragonbox] projects to make their implementation of
and
usable in constant expressions.
[fast_float] has an implementation of
limited to decimal string representation of floating-point numbers,
with state-of-the-art runtime performance.
Making this implementation usable from constant expressions was relatively straightforward.
The bulk of the work was adding
to all of the function declarations,
with some other minor changes here and there, using features available since C++20:
-
made it possible to navigate around compiler built-ins and otherstd :: is_constant_evaluated ()
-hostile constructs (intrinsics, getting current rounding mode) and use the already available generic fallback implementation instead.constexpr -
replacedstd :: bit_cast
for type punning.memcpy -
(std :: copy
since C++20) and related algorithms replacedconstexpr
for copying trivial ranges.memcpy
[dragonbox] has an implementation of
limited to decimal string representation of floating-point numbers,
with state-of-the-art runtime performance.
Making it work in constant expressions was similarly straightforward.
I am not aware of any implementation for the hexadecimal floating-point parts of these functions. I expect little implementation difficulty of handling hexadecimal floating-point representations, given that the algorithms for handling the decimal representation are vastly more complicated.
4. Wording
Wording is relative to [N5001].
4.1. [charconv.syn]
// 28.2.2, primitive numerical output conversion struct to_chars_result { // freestanding char* ptr; errc ec; friend bool operator==(const to_chars_result&, const to_chars_result&) = default; constexpr explicit operator bool() const noexcept { return ec == errc{}; } }; constexpr to_chars_result to_chars(char* first, char* last, // freestanding integer-type value, int base = 10); to_chars_result to_chars(char* first, char* last, // freestanding bool value, int base = 10) = delete; constexpr to_chars_result to_chars(char* first, char* last, // freestanding-deleted floating-point-type value); constexpr to_chars_result to_chars(char* first, char* last, // freestanding-deleted floating-point-type value, chars_format fmt); constexpr to_chars_result to_chars(char* first, char* last, // freestanding-deleted floating-point-type value, chars_format fmt, int precision); // 28.2.3, primitive numerical input conversion struct from_chars_result { // freestanding const char* ptr; errc ec; friend bool operator==(const from_chars_result&, const from_chars_result&) = default; constexpr explicit operator bool() const noexcept { return ec == errc{}; } }; constexpr from_chars_result from_chars(const char* first, const char* last, // freestanding integer-type& value, int base = 10); constexpr from_chars_result from_chars(const char* first, const char* last, // freestanding-deleted floating-point-type& value, chars_format fmt = chars_format::general); }
4.2. [charconv.to.chars]
constexpr to_chars_result to_chars(char* first, char* last, floating-point-type value);
constexpr to_chars_result to_chars(char* first, char* last, floating-point-type value, chars_format fmt);
constexpr to_chars_result to_chars(char* first, char* last, floating-point-type value, chars_format fmt, int precision);
4.3. [charconv.from.chars]
constexpr from_chars_result from_chars(const char* first, const char* last, floating-point-type & value, chars_format fmt = chars_format::general);
4.4. [version.syn]
#define __cpp_lib_constexpr_charconv202207LDATE-OF-ADOPTION // freestanding, also in <charconv>
5. Acknowledgements
I would like to thank Daniel Lemire and the contributors of [fast_float], as well as Junekey Jeon and the contributors of [dragonbox] for their work on their open-source libraries. Their efforts have been invaluable for making this proposal possible.