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 forfmt
has 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
fmt
haschars_format::scientific
set but notchars_format::fixed
, theotherwise optional exponent part shall appearexponent part is not optional;(7.3) — if
fmt
haschars_format::fixed
set but notchars_format::scientific
,the optional exponent part shall not appear; andthere is no exponent part;(?.?) — if
fmt
is notchars_format::hex
, only decimal digits and an optional'.'
appear before the exponent part (if any); and(7.4) — if
fmt
ischars_format::hex
, the prefix"0x"
or"0X"
is assumed. [Example: The string0x123
is parsed to have the value0
with remaining charactersx123
. — end example]In any case, the resulting
value
is 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:fmt
has 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 partINF
orINFINITY
, ignoring case;(7.2) —
ififfmt
haschars_format::scientific
set but notchars_format::fixed
, the otherwise optional exponent part shall appearnumeric_limits<T>::has_quiet_NaN
istrue
,NAN
orNAN(
n-char-sequenceopt)
, ignoring case in theNAN
part, where:n-char-sequence: digit nondigit n-char-sequence digit n-char-sequence nondigit;
(7.3) —
ififfmt
haschars_format::fixed
set but notchars_format::scientific
, the optional exponent part shall not appear; andfmt
is equal tochars_format::scientific
, a sequence of characters matching chars-format-dec exponent-part, where:chars-format-dec: fractional-constant digit-sequence;
(7.4) —
ififfmt
ischars_format::hex
, the prefix"0x"
or"0X"
is assumed. [Example: The string0x123
is parsed to have the value0
with remaining charactersx123
. — end example]fmt
is equal tochars_format::fixed
, a sequence of characters matching chars-format-dec;(?.?) — if
fmt
is equal tochars_format::general
, a sequence of characters matching chars-format-dec exponent-partopt; or(?.?) — if
fmt
is 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 offmt
limiting which forms of the subject sequence are recognized, and with no0x
or0X
prefix 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 resultingvalue
is one of at most two floating-point values closest to the value of the string matching the pattern.