Namespaces
Variants

std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get

来自 zh.cppreference.net
 
 
 
 
 
public:
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, bool& v ) const;
(1)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, long& v ) const;
(2)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, long long& v ) const;
(3) (自 C++11 起)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, unsigned short& v ) const;
(4)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, unsigned int& v ) const;
(5)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, unsigned long& v ) const;
(6)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, unsigned long long& v ) const;
(7) (自 C++11 起)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, float& v ) const;
(8)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, double& v ) const;
(9)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, long double& v ) const;
(10)
iter_type get( iter_type in, iter_type end, std::ios_base& str,
               std::ios_base::iostate& err, void*& v ) const;
(11)
protected:
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, bool& v ) const;
(12)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long& v ) const;
(13)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long long& v ) const;
(14) (自 C++11 起)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned short& v ) const;
(15)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned int& v ) const;
(16)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, unsigned long& v ) const;
(17)
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;
(18) (自 C++11 起)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, float& v ) const;
(19)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, double& v ) const;
(20)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, long double& v ) const;
(21)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
                          std::ios_base::iostate& err, void*& v ) const;
(22)
1-11) 公共成员函数,调用最派生类的成员函数 do_get。
12-22) 从输入迭代器读取字符 in,并生成类型 v 的值,考虑来自 str.flags() 的 I/O 流格式标志、来自 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
  • 对于整数类型,如有必要会向转换说明符添加长度修饰符: h 用于 short 和 unsigned short , l 用于 long 和 unsigned long , ll 用于 long long 和 unsigned long long (自 C++11 起)
  • 若 v 的类型为 float ,将使用转换说明符 % g
  • 若 v 的类型为 double ,将使用转换说明符 % lg
  • 若 v 的类型为 long double ,将使用转换说明符 % Lg
  • 若 v 的类型为 void * ,将使用转换说明符 % p
  • 若 v 的类型为 bool 且 boolalpha == 0 ,则按 v 的类型为 long 的方式处理,但在阶段 3 中存储到 v 的值除外。
  • 若 v 的类型为 bool 且 boolalpha ! = 0 ,以下内容将替换阶段 2 和 3:
    • 从输入迭代器 in 获取的连续字符,将根据 std:: use_facet < std:: numpunct < CharT >> ( str. getloc ( ) ) . falsename ( ) 和 std:: use_facet < std:: numpunct < CharT >> ( str. getloc ( ) ) . truename ( ) 获取的字符序列进行匹配,仅需匹配到能唯一识别为止。输入迭代器 in 仅在需要获取字符时才与 end 进行比较。
    • 若目标序列被唯一匹配, v 将被设为对应的 bool 值。否则将向 v 存储 false 并向 err 赋值 std::ios_base::failbit 。若在输入结束前( in == end )未能找到唯一匹配,则执行 err | = std:: ios_base :: eofbit 。

阶段2:字符提取

  • 如果in == end,阶段2立即终止,不再提取字符。
  • 下一个字符从in中提取,如同通过char_type ct = *in;:
    • 如果该字符匹配"0123456789abcdefxABCDEFX+-"(直到C++11)"0123456789abcdefpxABCDEFPX+-"(自C++11起)之一,通过std::use_facet<std::ctype<CharT>>(str.getloc()).widen()扩宽为本地环境的char_type,则将其转换为相应的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 的规则。
(C++11 前)
输入解析方式如下:
(C++11 起)
  • 若转换函数未能转换整个字段,则将值 ​ 0 ​ 存入 v 。
  • 若 v 为有符号整数类型且转换结果超出其表示范围,则分别存入该类型可表示的最大正值或最小负值至 v 。
  • 若 v 为无符号整数类型且转换结果超出其表示范围,则存入该类型可表示的最大正值至 v 。
  • 无论何种情况,若转换函数失败,则将 std::ios_base::failbit 赋值给 err 。
  • 否则,转换的数值结果将存入 v 。
    • 若 v 的类型为 bool 且未设置 boolalpha,则当待存储值为 ​ 0 ​ 时存入 false ,当待存储值为 1 时存入 true ,对于其他任何值则将 std::ios_base::failbit 赋值给 err 并存入 true 。
  • 随后检查数字分组:若在阶段2中被舍弃的千位分隔符位置与 std:: use_facet < std:: numpunct < CharT >> ( str. getloc ( ) ) . grouping ( ) 所提供的分组规则不匹配,则将 std::ios_base::failbit 赋值给 err 。
  • 若阶段2因条件 in == end 而终止,则执行 err | = std:: ios_base :: eofbit 以设置 eof 位。

返回值

in

注释

在 LWG issue 23 和 LWG issue 696 的决议通过之前, v 在发生错误时保持未更改状态。

在 LWG 问题 221 解决之前,表示十六进制整数的字符串(例如 "0xA0" )会被 do_get(int) 拒绝,即使它们是 strtol 的有效输入,因为阶段 2 会过滤掉字符 'X' 和 'x' 。

在 LWG issue 1169 解决之前,将负数字符串转换为无符号整数可能产生零(因为字符串表示的数值小于目标类型所能表示的范围)。

在解决 LWG 问题 2381 之前,即使是指数形式的十六进制浮点数表示字符串(例如 "0x1.23p-10" )能够作为 strtod 的有效输入,也会被 do_get(double) 拒绝,因为阶段2会过滤掉字符 'P' 和 'p' 。

表示无穷大或非数字的字符串(例如 "NaN" 和 "inf" )即使能够作为 strtod 的有效输入,也会被 do_get(double) 拒绝,因为阶段2会过滤掉诸如 'N' 或 'i' 等字符。

(C++11 起)

示例

用户自定义类型的 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 // setting err could throw
    {
        typename std::basic_istream<CharT, Traits>::sentry s(is);
        if (s) // if stream is ready for input
            std::use_facet<std::num_get<CharT>>(is.getloc()).get(is, {}, is, err, b.x);
    }
    catch (std::ios_base::failure& error)
    {
        // handle the exception
    }
    return is;
}
int main()
{
    base b;
    std::cin >> b;
}

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的C++标准。

问题报告 适用标准 发布行为 正确行为
LWG 17 C++98 文本布尔值解析过程存在错误 已修正
LWG 18 C++98 接受 get 的 bool & 参数的重载缺失 已添加
LWG 23 C++98 输入溢出导致未定义行为 溢出已处理
LWG 154 C++98 double 的转换说明符为 % g (与 float 相同) 改为 % lg
LWG 221 C++98 do_get 未解析 'x' 和 'X' ,而 strtol 会解析它们 使 'x' 和 'X' 可被解析
LWG 275 C++98 get 存在接受 short & 参数的重载,而非 float & 已修正
LWG 358 C++98 小数点后的千位分隔符被忽略 遇到时终止阶段2
LWG 696 C++98 转换失败时结果保持不变 设置为零
LWG 1169 C++98 浮点类型的溢出处理不一致 与 strtof / strtod 保持一致
LWG 2381 C++11 do_get 未解析 'p' 和 'P' ,而 strtod 会解析它们 使 'p' 和 'P' 可被解析

另请参阅

提取格式化数据
( std::basic_istream<CharT,Traits> 的公开成员函数)