std::num_get::get, std::num_get::do_get

来自cppreference.com
< cpp‎ | locale‎ | num get
(1)
public:

iter_type get( iter_type in, iter_type end, std::ios_base& str,

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

virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,

                          std::ios_base::iostate& err, bool& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned short& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned int& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned long long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, float& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, double& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long double& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, void*& v ) const;
1) 公开成员函数,调用最终导出类的成员函数 do_get
2) 从输入迭代器 in 读取字符,并生成 v 的类型的值,考虑来自 IO 流 str.flags() 的格式化标志,来自 std::use_facet<std::ctype<charT>>(str.getloc()) 的字符分类规则,和来自 std::use_facet<std::numpunct<charT>>(str.getloc()) 的数值标点字符。此函数为所有有格式输入流运算符,如 std::cin >> n; 所调用。

转换在三个阶段出现

目录

[编辑] 阶段 1 :转换指定符选择

  • 获得 I/O 格式化标志,如同以
fmtflags basefield = (str.flags() & std::ios_base::basefield);
fmtflags boolalpha = (str.flags() & std::ios_base::boolalpha);
  • v 的类型为整数类型,则选择下列五个选项的首个可应用者:
basefield == oct ,则将使用转换指定符 %o
basefield == hex ,则将使用转换指定符 %X
basefield == 0 ,则将使用转换指定符 %i
v 的类型有符号,则将使用转换指定符 %d
v 的类型无符号,则将使用转换指定符 %u
  • 对于整数类型,若需要则添加长度指定符到转换指定:对于 shortunsigned shorth ,对于 longunsigned longl ,对于 long longunsigned long longll
  • v 的类型为 float ,则将使用转换指定符 %g
  • v 的类型为 double ,则将使用转换指定符 %lg
  • v 的类型为 long double ,则将使用转换指定符 %Lg
  • v 的类型为 void* ,则将使用转换指定符 %p
  • v 的类型为 boolboolalpha==0 ,则如同按 v 的类型为 long 一般处理,除了在阶段 3 存储于 v 的值。
  • v 的类型为 boolboolalpha!=0 ,则下列规则替换阶段 2 和 3 :
    • 从输入迭代器 in 获得匹配获得自 std::use_facet<std::numpunct<charT>>(str.getloc()).falsename()std::use_facet<std::numpunct<charT> >(str.getloc()).truename() 的相继字符,而且仅按需要匹配鉴别唯一匹配。仅在需要获得字符时,将输入迭代器 inend 比较。
    • 若目标序列为唯一匹配,则设置 v 为对应的 bool 值。否则存储 falsev 并赋值 std::ios_base::failbiterr 。若在输入结束( in==end )前无法找到唯一匹配,则执行 err|=std::ios_base::eofbit

[编辑] 阶段 2 :字符释出

  • in==end ,则立即终止阶段 2 ,则不再释出更多字符
  • 如同以 char_type ct = *in;in 释出下个字符
    • 若字符匹配如同用 std::use_facet<std::ctype<charT>>(str.getloc()).widen() 加宽到 locale 的 char_type 的 "0123456789abcdefxABCDEFX+-" 字符之一,则将它转换为对应的 char
    • 若字符匹配小数点( std::use_facet<std::numpunct<charT>>(str.getloc()).decimal_point()) ),则以 '.' 替换之。
    • 若字符匹配千分隔符( std::use_facet<std::numpunct<charT>>(str.getloc()).thousands_sep() )且在所有 std::use_facet<std::numpunct<charT>>(str.getloc()).grouping().length() != 0 中使用千分隔,则若尚未积累小数点 '.' ,则记忆该字符的位置,但其他情况下忽略该字符。若已基类小数点,则舍弃该字符并终止阶段 2 。
    • 任何情况下,检查从前一步骤获得的 char 是否在会为 std::scanf 给定阶段 1 中选择的转换指定符的输入域中得到允许。若它手允许,则将它积累到临时缓冲区并重复阶段 2 。若它不受允许,则阶段 2 终止。

[编辑] 阶段 3 :转换与存储

  • 转换阶段 2 中积累的 char 序列为数值
输入如同以 std::scanf 带阶段 1 中选择的转换指定符分析
(C++11 前)
输入如同以对 v 有符号整数的 std::strtoll 、对无符号整数 vstd::strtoull 或对浮点 vstd::strtold 分析
(C++11 起)
(C++17 前)
输入如同以对有符号整数 vstd::strtoll 、对无符号整数 vstd::strtoull 、对 float vstd::strtof 、对 double vstd::strtod 或对 long double vstd::strtold 分析
(C++17 起)
  • 若转换函数无法转换整个域,则存储值 0v
  • 若转换函数产生过大而无法适合 v 类型的正值,则存储可表示的最正值于 v
  • 若转换函数产生过大而无法适合 v 类型的负值,则存储可表示的最负值于 v ,或对于无符号整数类型为零 (C++17 前)
(C++11 起)
  • 任何情况下,若转换函数失败,则赋值 std::ios_base::failbiterr
  • 否则,存储转换的数值结果于 v
    • v 的类型为 bool 且未设置 boolalpha ,则若要存储的值为 0 则存储 false ,若要存储的值为 1 则存储 true ,对于任何其他值,赋值 std::ios_base::failbiterr 并存储 true
  • 之后,检查数位分组。若阶段 2 中舍弃的任何千分隔符的位置不匹配 std::use_facet<std::numpunct<charT>>(str.getloc()).grouping() 所提供的分组,则赋值 std::ios_base::failbiterr
  • 若因测试 in==end 终止阶段 2 ,则执行 err|=std::ios_base::eofbit 设置 eof 位。

[编辑] 返回值

in

[编辑] 注意

C++98/C++03 中,若出现错误,则保留 v 不更改。 C++11 中,它被设为上述的值。

C++17 前,转换负整数字符串为无符号整数曾被指定为产生零,尽管某些实现遵循了 std::strtoull 的协议,对 "-1" 给出 ULLONG_MAX ,故替而产生目标类型的最大值。 C++17 起,严格遵循 std::strtoull 是正确行为。

因为阶段 2 滤出如 'p' 、 'N' 或 'i' 的字符,如 "0x1.23p-10" 的十六进制浮点数和字符串 "NaN" 或 "inf" 可能为 do_get(double) 所拒绝,即使它们它们是对 strtod 的合法输入:此为 LWG #2381

[编辑] 示例

用户定义类型的 operator>> 实现。

#include <iostream>
#include <iterator>
#include <locale>
 
struct base { long x; };
 
template <class CharT, class Traits>
std::basic_istream<CharT, Traits>&
    operator >>(std::basic_istream<CharT, Traits>& is,
                base& b)
{
    std::ios_base::iostate err = std::ios_base::goodbit;
    try // 设置 err 为能抛出
    {
        typename std::basic_istream<CharT, Traits>::sentry s(is);
 
        if (s) // 若流已为输入就绪
        {
            std::use_facet<std::num_get<CharT>>(is.getloc()).get(is, {}, is, err, b.x);
        }
    } catch(std::ios_base::failure& error)
    {
        // 处理异常
    }
    return is;
}
 
int main()
{
    base b;
 
    std::cin >> b;
}


[编辑] 参阅

释出有格式数据
(std::basic_istream 的公开成员函数) [编辑]