std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get
来自 cppreference.cn
(1) | ||
public: iter_type get( iter_type in, iter_type end, std::ios_base& str, |
||
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, |
||
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; |
(自 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; |
||
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, |
(自 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; |
||
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 类型的值,同时考虑来自 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 起) 之一匹配,拓宽到区域设置的 char_type,如同通过 std::use_facet<std::ctype<CharT>>(str.getloc()).widen(),则将其转换为相应的 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 序列被转换为数值
|
(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 issue 221 的决议之前,即使十六进制整数字符串(例如 "0xA0")是 strtol 的有效输入,也会被 do_get(int)
拒绝,因为阶段 2 过滤掉了字符 'X' 和 'x'。
在 LWG issue 1169 的决议之前,将负数字符串转换为无符号整数可能会产生零(因为字符串表示的值小于目标类型可以表示的值)。
在 LWG issue 2381 的决议之前,即使十六进制浮点数带指数的字符串(例如 "0x1.23p-10")是 strtod 的有效输入,也会被 表示无穷大或非数字的字符串(例如 "NaN" 和 "inf")即使是 |
(自 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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
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& value 而不是 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> 的公有成员函数) |