This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
std::from_chars is underspecifiedSection: 28.2.3 [charconv.from.chars] Status: New Submitter: Jonathan Wakely Opened: 2020-06-23 Last modified: 2020-09-06
Priority: 3
View other active issues in [charconv.from.chars].
View all other issues in [charconv.from.chars].
View all issues with New status.
Discussion:
The intention of 28.2.3 [charconv.from.chars] p7 is that the fmt argument modifies
the expected pattern, so that only a specific subset of valid strtod patterns are recognized
for each format. This is not clear from the wording.
fmt == chars_format::fixed no exponent is to be used, so any trailing characters that match
the form of a strtod exponent are ignored. For example, "1.23e4" should produce the result
1.23 for the fixed format. The current wording says "the optional exponent part shall not appear"
which can be interpreted to mean that "1.23e4" violates a precondition and so has undefined behaviour!
When fmt != chars_format::hex only decimal numbers should be recognized. This means that for any
format except scientific, "0x123" produces 0.0 (it's invalid when
fmt == chars_format::scientific because there's no exponent). The current wording only says that
when hex is used the string has an assumed "0x" prefix, so is interpreted as a hexadecimal
float, it doesn't say that when fmt != hex that the string is not interpreted as a
hexadecimal float.
Two alternative resolutions are provided, one is a minimal fix and the other attempts to make it clearer by
not referring to a modified version of the C rules.
[2020-07-14; Jonathan fixes the strtod call in Option B]
[2020-07-17; Priority set to 3 in telecon]
Proposed resolution:
This wording is relative to N4861.
Option A:Modify 28.2.3 [charconv.from.chars] as indicated:
from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt = chars_format::general); from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt = chars_format::general); from_chars_result from_chars(const char* first, const char* last, long double& value, chars_format fmt = chars_format::general);-6- Preconditions:
-7- Effects: The pattern is the expected form of the subject sequence in the "C" locale, as described forfmthas the value of one of the enumerators ofchars_format.strtod, except that
(7.1) — the sign
'+'may only appear in the exponent part;(7.2) — if
fmthaschars_format::scientificset but notchars_format::fixed, theotherwise optional exponent part shall appearexponent part is not optional;(7.3) — if
fmthaschars_format::fixedset but notchars_format::scientific,the optional exponent part shall not appear; andthere is no exponent part;(?.?) — if
fmtis notchars_format::hex, only decimal digits and an optional'.'appear before the exponent part (if any); and(7.4) — if
fmtischars_format::hex, the prefix"0x"or"0X"is assumed. [Example: The string0x123is parsed to have the value0with remaining charactersx123. — end example]In any case, the resulting
valueis one of at most two floating-point values closest to the value of the string matching the pattern.
Modify 28.2.3 [charconv.from.chars] as indicated:
from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt = chars_format::general); from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt = chars_format::general); from_chars_result from_chars(const char* first, const char* last, long double& value, chars_format fmt = chars_format::general);-6- Preconditions:
-7- Effects:fmthas the value of one of the enumerators ofchars_format.The pattern is the expected form of the subject sequence in the "C" locale, as described forThe pattern is an optionalstrtod, except that'-'sign followed by one of:
(7.1) —
the sign'+'may only appear in the exponent partINForINFINITY, ignoring case;(7.2) —
ififfmthaschars_format::scientificset but notchars_format::fixed, the otherwise optional exponent part shall appearnumeric_limits<T>::has_quiet_NaNistrue,NANorNAN(n-char-sequenceopt), ignoring case in theNANpart, where:n-char-sequence: digit nondigit n-char-sequence digit n-char-sequence nondigit;
(7.3) —
ififfmthaschars_format::fixedset but notchars_format::scientific, the optional exponent part shall not appear; andfmtis equal tochars_format::scientific, a sequence of characters matching chars-format-dec exponent-part, where:chars-format-dec: fractional-constant digit-sequence;
(7.4) —
ififfmtischars_format::hex, the prefix"0x"or"0X"is assumed. [Example: The string0x123is parsed to have the value0with remaining charactersx123. — end example]fmtis equal tochars_format::fixed, a sequence of characters matching chars-format-dec;(?.?) — if
fmtis equal tochars_format::general, a sequence of characters matching chars-format-dec exponent-partopt; or(?.?) — if
fmtis equal tochars_format::hex, a sequence of characters matching chars-format-hex binary-exponent-partopt, where:chars-format-hex: hexadecimal-fractional-constant hexadecimal-digit-sequence[Note: The pattern is derived from the subject sequence in the
"C"locale forstrtod, with the value offmtlimiting which forms of the subject sequence are recognized, and with no0xor0Xprefix recognized. — end note]For a character sequence
INF,INFINITY,NAN, orNAN(n-char-sequenceopt)the resulting value is obtained as if by evaluatingstrtod(string(first, last).c_str(), nullptr)in the"C"locale. In all other casesIn any case, the resultingvalueis one of at most two floating-point values closest to the value of the string matching the pattern.