1. Revision history
1.1. R1
-
Add [P3391R0] to motivation.
-
Add [fmt] and [musl_from_chars] to implementation experience.
2. Proposal
I propose to make the and functions for floating-point types usable in constant expressions.
3. 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), [P2758R4] (emitting messages at compile time) and [P3391R0] (constexpr ).
4. 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.
[fmt] uses [dragonbox] to format and , and also has support
(godbolt).
[musl_from_chars] is a work-in-progress implementation of with support based on the implementation of in [musl]. It supports , and .
It supports platforms where is IEEE 754 binary64, x87 extended-precision or IEEE 754 binary128.
It supports parsing both decimal and hexidecimal representations
(godbolt).
5. Wording
Wording is relative to [N5001].
5.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);
}
5.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);
5.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);
5.4. [version.syn]
#define __cpp_lib_constexpr_charconv202207LDATE-OF-ADOPTION // freestanding, also in <charconv>
6. 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.