22 Localization library [localization]

22.4 Standard locale categories [locale.categories]

22.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.246

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 [tab:localization.category.facets] and [tab:localization.required.specializations] ([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.

22.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:
    typedef charT            char_type;
    typedef InputIterator    iter_type;

    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.

22.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).

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

  • 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 [tab:localization.integer.conversions.in]. The table is ordered. That is, the first line whose condition is true applies.

    Table 85 — 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 [tab:localization.length.modifier.in].

    Table 86 — 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
  • 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.

  • 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 floating-point value, the function strtold.

    The numeric value to be stored can be one of:

    • zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.

    • the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.

    • the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.

    • the converted value, otherwise.

    The resultant numeric value is stored in val.

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.

22.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:
    typedef charT            char_type;
    typedef OutputIterator   iter_type;

    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.

22.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).

22.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 determining 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.

  • 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));
    

    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 [tab:localization.integer.conversions.out].

    Table 87 — 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 [tab:localization.fp.conversions.out].

    Table 88 — 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 [tab:localization.length.modifier.out].

    Table 89 — 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 [tab:localization.numeric.conversions].

    Table 90 — Numeric conversions
    Type(s)State stdio equivalent
    an integral type flags & showpos +
    flags & showbase #
    a floating-point type flags & showpos +
    flags & 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.

  • 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()

  • A local variable is initialized as

    fmtflags adjustfield=   (flags & (ios_base::adjustfield));
    

    The location of any padding247 is determined according to Table [tab:localization.fill.padding].

    Table 91 — 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.

  • 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<ctype<charT> >(loc).truename()
    : use_facet<ctype<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.