Namespaces
Variants

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

From cppreference.net
std::num_get
Member functions
num_get::get num_get::do_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 ;
(自 C++11 起)
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 ;
(自 C++11 起)
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 ;
<span class="t-mark-rev t-since
1) 公开成员函数,调用最派生类的成员函数 do_get
2) 从输入迭代器 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 值。否则将 false 存储到 v 中,并将 std::ios_base::failbit 赋给 err 。若在输入结束前未能找到唯一匹配( 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 >(str.getloc()).widen() 扩展为本地环境的 char_type),则将其转换为对应的 char
    • 若该字符匹配小数点分隔符( std::use_facet >(str.getloc()).decimal_point() ),则将其替换为 '.'
    • 若该字符匹配千位分隔符( std::use_facet >(str.getloc()).thousands_sep() )且启用了千位分隔(由 std::use_facet >(str.getloc()).grouping().length() != 0 确定):若尚未累积小数点 '.' ,则记录该字符的位置但忽略该字符;若已累积小数点,则丢弃该字符并终止阶段2。
    • 无论如何,都会检查前几步获得的 char 是否允许出现在由阶段1选定的转换说明符对应的 std::scanf 输入字段中。若允许,则将其累积到临时缓冲区并重复阶段2;若不允许,则终止阶段2。

阶段3:转换与存储

  • 在阶段2中累积的 char 序列将被转换为数值:
输入按照 std::scanf 的规则进行解析。
(C++11 前)
输入解析方式如下:
(C++11 起)
  • 如果转换函数未能转换整个字段,则值 0 将被存储到 v 中。
  • 如果 v 的类型为有符号整数类型,且转换函数产生的正值或负值超出其可容纳范围,则分别将可表示的最大正值或最小负值存储到 v 中。
  • 如果 v 的类型为无符号整数类型,且转换函数产生的值超出其可容纳范围,则将可表示的最大正值存储到 v 中。
  • 无论何种情况,若转换函数失败,则向 err 设置 std::ios_base::failbit
  • 否则,转换的数值结果将存储到 v 中。
    • 如果 v 的类型为 bool 且未设置 boolalpha,则当待存储值为 0 时存储 false ,当待存储值为 1 时存储 true ,对于其他任何值则向 err 设置 std::ios_base::failbit 并存储 true
  • 此后检查数字分组:若在第2阶段被舍弃的千位分隔符位置与 std:: use_facet < std:: numpunct < CharT >> ( str. getloc ( ) ) . grouping ( ) 提供的分组不匹配,则向 err 设置 std::ios_base::failbit
  • 若第2阶段因条件 in == end 而终止,则执行 err | = std:: ios_base :: eofbit 来设置 eof 位。

返回值

in

注释

LWG issue 23 LWG issue 696 的决议之前,若发生错误, v 将保持不变。

LWG issue 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 缺失接受 bool & 参数的 get 重载 已添加
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 忽略小数点后的千位分隔符 遇到时终止第二阶段解析
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> 的公开成员函数)