25 Localization library [localization]

25.4 Standard locale categories [locale.categories]

25.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.239

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 69 and 70 ([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.

25.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.

25.4.2.1.1 num_­get 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).

25.4.2.1.2 num_­get 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 73. The table is ordered. That is, the first line whose condition is true applies.

    Table 73 — Integer conversions
    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 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 74.

    Table 74 — Length modifier
    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.

25.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.

25.4.2.2.1 num_­put 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).

25.4.2.2.2 num_­put 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, a local variable initialized with:

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>>(str.getloc())

  • 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 75.

    Table 75 — Integer conversions
    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 76.

    Table 76 — Floating-point conversions
    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 77.

    Table 77 — Length modifier
    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 78.

    Table 78 — Numeric conversions
    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>>(str.getloc());

    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 padding240 is determined according to Table 79.

    Table 79 — Fill padding
    StateLocation
    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.