28 Localization library [localization]

28.4 Standard locale categories [locale.categories]

28.4.2 The numeric category [category.numeric]

The classes num_­get<> and num_­put<> handle numeric formatting and parsing.
Virtual functions are provided for several numeric types.
Implementations may (but are not required to) delegate extraction of smaller types to extractors for larger types.266
All specifications of member functions for num_­put and num_­get in the subclauses of [category.numeric] only apply to the specializations required in Tables 102 and 103 ([locale.category]), namely num_­get<char>, num_­get<wchar_­t>, num_­get<C, InputIterator>, num_­put<char>, num_­put<wchar_­t>, and num_­put<C, OutputIterator>.
These specializations refer to the ios_­base& argument for formatting specifications ([locale.categories]), and to its imbued locale for the numpunct<> facet to identify all numeric punctuation preferences, and also for the ctype<> facet to perform character classification.
Extractor and inserter members of the standard iostreams use num_­get<> and num_­put<> member functions for formatting and parsing numeric values ([istream.formatted.reqmts], [ostream.formatted.reqmts]).
Parsing "-1" correctly into, e.g., an unsigned short requires that the corresponding member get() at least extract the sign before delegating.

28.4.2.1 Class template num_­get [locale.num.get]

namespace std {
  template<class charT, class InputIterator = istreambuf_iterator<charT>>
    class num_get : public locale::facet {
    public:
      using char_type = charT;
      using iter_type = InputIterator;

      explicit num_get(size_t refs = 0);

      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, bool& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, long& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, long long& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, unsigned short& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, unsigned int& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, unsigned long& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, unsigned long long& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, float& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, double& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, long double& v) const;
      iter_type get(iter_type in, iter_type end, ios_base&,
                    ios_base::iostate& err, void*& v) const;

      static locale::id id;

    protected:
      ~num_get();
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, bool& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, long& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, long long& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, unsigned short& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, unsigned int& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, unsigned long& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, unsigned long long& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, float& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, double& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, long double& v) const;
      virtual iter_type do_get(iter_type, iter_type, ios_base&,
                               ios_base::iostate& err, void*& v) const;
    };
}
The facet num_­get is used to parse numeric values from an input sequence such as an istream.

28.4.2.1.1 Members [facet.num.get.members]

iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, bool& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long long& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned short& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned int& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned long& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned long long& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, float& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, double& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long double& val) const; iter_type get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, void*& val) const;
Returns: do_­get(in, end, str, err, val).

28.4.2.1.2 Virtual functions [facet.num.get.virtuals]

iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long long& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned short& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned int& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned long& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, unsigned long long& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, float& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, double& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, long double& val) const; iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, void*& val) const;
Effects: Reads characters from in, interpreting them according to str.flags(), use_­facet<ctype<​charT>>(loc), and use_­facet<numpunct<charT>>(loc), where loc is str.getloc().
The details of this operation occur in three stages
  • Stage 1: Determine a conversion specifier
  • Stage 2: Extract characters from in and determine a corresponding char value for the format expected by the conversion specification determined in stage 1.
  • Stage 3: Store results
The details of the stages are presented below.
  • Stage 1:
    The function initializes local variables via
    fmtflags flags = str.flags();
    fmtflags basefield = (flags & ios_base::basefield);
    fmtflags uppercase = (flags & ios_base::uppercase);
    fmtflags boolalpha = (flags & ios_base::boolalpha);
    
    For conversion to an integral type, the function determines the integral conversion specifier as indicated in Table 106.
    The table is ordered.
    That is, the first line whose condition is true applies.
    Table 106: Integer conversions   [tab:facet.num.get.int]
    State
    stdio equivalent
    basefield == oct
    %o
    basefield == hex
    %X
    basefield == 0
    %i
    signed integral type
    %d
    unsigned integral type
    %u
    For conversions to a floating-point type the specifier is %g.
    For conversions to void* the specifier is %p.
    A length modifier is added to the conversion specification, if needed, as indicated in Table 107.
    Table 107: Length modifier   [tab:facet.num.get.length]
    Type
    Length modifier
    short
    h
    unsigned short
    h
    long
    l
    unsigned long
    l
    long long
    ll
    unsigned long long
    ll
    double
    l
    long double
    L
  • Stage 2:
    If in == end then stage 2 terminates.
    Otherwise a charT is taken from in and local variables are initialized as if by
    char_type ct = *in;
    char c = src[find(atoms, atoms + sizeof(src) - 1, ct) - atoms];
    if (ct == use_facet<numpunct<charT>>(loc).decimal_point())
    c = '.';
    bool discard =
      ct == use_facet<numpunct<charT>>(loc).thousands_sep()
      && use_facet<numpunct<charT>>(loc).grouping().length() != 0;
    
    where the values src and atoms are defined as if by:
    static const char src[] = "0123456789abcdefxABCDEFX+-";
    char_type atoms[sizeof(src)];
    use_facet<ctype<charT>>(loc).widen(src, src + sizeof(src), atoms);
    
    for this value of loc.
    If discard is true, then if '.' has not yet been accumulated, then the position of the character is remembered, but the character is otherwise ignored.
    Otherwise, if '.' has already been accumulated, the character is discarded and Stage 2 terminates.
    If it is not discarded, then a check is made to determine if c is allowed as the next character of an input field of the conversion specifier returned by Stage 1.
    If so, it is accumulated.
    If the character is either discarded or accumulated then in is advanced by ++in and processing returns to the beginning of stage 2.
  • Stage 3:
    The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:
    • For a signed integer value, the function strtoll.
    • For an unsigned integer value, the function strtoull.
    • For a float value, the function strtof.
    • For a double value, the function strtod.
    • For a long double value, the function strtold.
    The numeric value to be stored can be one of:
    • zero, if the conversion function does not convert the entire field.
    • the most positive (or negative) representable value, if the field to be converted to a signed integer type represents a value too large positive (or negative) to be represented in val.
    • the most positive representable value, if the field to be converted to an unsigned integer type represents a value that cannot be represented in val.
    • the converted value, otherwise.
    The resultant numeric value is stored in val.
    If the conversion function does not convert the entire field, or if the field represents a value outside the range of representable values, ios_­base​::​failbit is assigned to err.
Digit grouping is checked.
That is, the positions of discarded separators is examined for consistency with use_­facet<numpunct<charT>>(loc).grouping().
If they are not consistent then ios_­base​::​failbit is assigned to err.
In any case, if stage 2 processing was terminated by the test for in == end then err |= ios_­base​::​eofbit is performed.
iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, bool& val) const;
Effects: If (str.flags()&ios_­base​::​boolalpha) == 0 then input proceeds as it would for a long except that if a value is being stored into val, the value is determined according to the following: If the value to be stored is 0 then false is stored.
If the value is 1 then true is stored.
Otherwise true is stored and ios_­base​::​failbit is assigned to err.
Otherwise target sequences are determined “as if” by calling the members falsename() and truename() of the facet obtained by use_­facet<numpunct<charT>>(str.getloc()).
Successive characters in the range [in, end) (see [sequence.reqmts]) are obtained and matched against corresponding positions in the target sequences only as necessary to identify a unique match.
The input iterator in is compared to end only when necessary to obtain a character.
If a target sequence is uniquely matched, val is set to the corresponding value.
Otherwise false is stored and ios_­base​::​failbit is assigned to err.
The in iterator is always left pointing one position beyond the last character successfully matched.
If val is set, then err is set to str.goodbit; or to str.eofbit if, when seeking another character to match, it is found that (in == end).
If val is not set, then err is set to str.failbit; or to (str.failbit|str.eofbit) if the reason for the failure was that (in == end).
[Example
:
For targets true: "a" and false: "abb", the input sequence "a" yields val == true and err == str.eofbit; the input sequence "abc" yields err = str.failbit, with in ending at the 'c' element.
For targets true: "1" and false: "0", the input sequence "1" yields val == true and err == str.goodbit.
For empty targets (""), any input sequence yields err == str.failbit.
— end example
]
Returns: in.

28.4.2.2 Class template num_­put [locale.nm.put]

namespace std {
  template<class charT, class OutputIterator = ostreambuf_iterator<charT>>
    class num_put : public locale::facet {
    public:
      using char_type = charT;
      using iter_type = OutputIterator;

      explicit num_put(size_t refs = 0);

      iter_type put(iter_type s, ios_base& f, char_type fill, bool v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, long v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, long long v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, unsigned long v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, unsigned long long v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, double v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, long double v) const;
      iter_type put(iter_type s, ios_base& f, char_type fill, const void* v) const;

      static locale::id id;

    protected:
      ~num_put();
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, bool v) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, long v) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, long long v) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, unsigned long) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, unsigned long long) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, double v) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, long double v) const;
      virtual iter_type do_put(iter_type, ios_base&, char_type fill, const void* v) const;
    };
}
The facet num_­put is used to format numeric values to a character sequence such as an ostream.

28.4.2.2.1 Members [facet.num.put.members]

iter_type put(iter_type out, ios_base& str, char_type fill, bool val) const; iter_type put(iter_type out, ios_base& str, char_type fill, long val) const; iter_type put(iter_type out, ios_base& str, char_type fill, long long val) const; iter_type put(iter_type out, ios_base& str, char_type fill, unsigned long val) const; iter_type put(iter_type out, ios_base& str, char_type fill, unsigned long long val) const; iter_type put(iter_type out, ios_base& str, char_type fill, double val) const; iter_type put(iter_type out, ios_base& str, char_type fill, long double val) const; iter_type put(iter_type out, ios_base& str, char_type fill, const void* val) const;
Returns: do_­put(out, str, fill, val).

28.4.2.2.2 Virtual functions [facet.num.put.virtuals]

iter_type do_put(iter_type out, ios_base& str, char_type fill, long val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, long long val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long long val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, double val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, long double val) const; iter_type do_put(iter_type out, ios_base& str, char_type fill, const void* val) const;
Effects: Writes characters to the sequence out, formatting val as desired.
In the following description, loc names a local variable initialized as
locale loc = str.getloc();
The details of this operation occur in several stages:
  • Stage 1: Determine a printf conversion specifier spec and determine the characters that would be printed by printf ([c.files]) given this conversion specifier for
    printf(spec, val)
    
    assuming that the current locale is the "C" locale.
  • Stage 2: Adjust the representation by converting each char determined by stage 1 to a charT using a conversion and values returned by members of use_­facet<numpunct<charT>>(loc).
  • Stage 3: Determine where padding is required.
  • Stage 4: Insert the sequence into the out.
Detailed descriptions of each stage follow.
Returns: out.
  • Stage 1:
    The first action of stage 1 is to determine a conversion specifier.
    The tables that describe this determination use the following local variables
    fmtflags flags = str.flags();
    fmtflags basefield =  (flags & (ios_base::basefield));
    fmtflags uppercase =  (flags & (ios_base::uppercase));
    fmtflags floatfield = (flags & (ios_base::floatfield));
    fmtflags showpos =    (flags & (ios_base::showpos));
    fmtflags showbase =   (flags & (ios_base::showbase));
    fmtflags showpoint =  (flags & (ios_base::showpoint));
    
    All tables used in describing stage 1 are ordered.
    That is, the first line whose condition is true applies.
    A line without a condition is the default behavior when none of the earlier lines apply.
    For conversion from an integral type other than a character type, the function determines the integral conversion specifier as indicated in Table 108.
    Table 108: Integer conversions   [tab:facet.num.put.int]
    State
    stdio equivalent
    basefield == ios_­base​::​oct
    %o
    (basefield == ios_­base​::​hex) && !uppercase
    %x
    (basefield == ios_­base​::​hex)
    %X
    for a signed integral type
    %d
    for an unsigned integral type
    %u
    For conversion from a floating-point type, the function determines the floating-point conversion specifier as indicated in Table 109.
    Table 109: Floating-point conversions   [tab:facet.num.put.fp]
    State
    stdio equivalent
    floatfield == ios_­base​::​fixed
    %f
    floatfield == ios_­base​::​scientific && !uppercase
    %e
    floatfield == ios_­base​::​scientific
    %E
    floatfield == (ios_­base​::​fixed | ios_­base​::​scientific) && !uppercase
    %a
    floatfield == (ios_­base​::​fixed | ios_­base​::​scientific)
    %A
    !uppercase
    %g
    otherwise
    %G
    For conversions from an integral or floating-point type a length modifier is added to the conversion specifier as indicated in Table 110.
    Table 110: Length modifier   [tab:facet.num.put.length]
    Type
    Length modifier
    long
    l
    long long
    ll
    unsigned long
    l
    unsigned long long
    ll
    long double
    L
    otherwise
    none
    The conversion specifier has the following optional additional qualifiers prepended as indicated in Table 111.
    Table 111: Numeric conversions   [tab:facet.num.put.conv]
    Type(s)
    State
    stdio equivalent
    an integral type
    showpos
    +
    showbase
    #
    a floating-point type
    showpos
    +
    showpoint
    #
    For conversion from a floating-point type, if floatfield != (ios_­base​::​fixed | ios_­base​::​​scientific), str.precision() is specified as precision in the conversion specification.
    Otherwise, no precision is specified.
    For conversion from void* the specifier is %p.
    The representations at the end of stage 1 consists of the char's that would be printed by a call of printf(s, val) where s is the conversion specifier determined above.
  • Stage 2:
    Any character c other than a decimal point(.) is converted to a charT via
    use_facet<ctype<charT>>(loc).widen(c)
    
    A local variable punct is initialized via
    const numpunct<charT>& punct = use_facet<numpunct<charT>>(loc);
    
    For arithmetic types, punct.thousands_­sep() characters are inserted into the sequence as determined by the value returned by punct.do_­grouping() using the method described in [facet.numpunct.virtuals]
    Decimal point characters(.) are replaced by punct.decimal_­point()
  • Stage 3:
    A local variable is initialized as
    fmtflags adjustfield = (flags & (ios_base::adjustfield));
    
    The location of any padding267 is determined according to Table 112.
    Table 112: Fill padding   [tab:facet.num.put.fill]
    State
    Location
    adjustfield == ios_­base​::​left
    pad after
    adjustfield == ios_­base​::​right
    pad before
    adjustfield == internal and a sign occurs in the representation
    pad after the sign
    adjustfield == internal and representation after stage 1 began with 0x or 0X
    pad after x or X
    otherwise
    pad before
    If str.width() is nonzero and the number of charT's in the sequence after stage 2 is less than str.​width(), then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence to str.width().
    str.width(0) is called.
  • Stage 4:
    The sequence of charT's at the end of stage 3 are output via
    *out++ = c
    
iter_type do_put(iter_type out, ios_base& str, char_type fill, bool val) const;
Returns: If (str.flags() & ios_­base​::​boolalpha) == 0 returns do_­put(out, str, fill,
(int)val)
, otherwise obtains a string s as if by
string_type s =
  val ? use_facet<numpunct<charT>>(loc).truename()
      : use_facet<numpunct<charT>>(loc).falsename();
and then inserts each character c of s into out via *out++ = c and returns out.
The conversion specification #o generates a leading 0 which is not a padding character.