std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get
来自cppreference.com
| (1) | ||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
| |
||
| (2) | ||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
| |
||
1) 公开成员函数,调用最终派生类的成员函数
do_get。2) 从输入迭代器
in 读取字符,并生成 v 的类型的值,考虑来自输入/输出流 str.flags() 的格式化标志,来自 std::use_facet<std::ctype<CharT>>(str.getloc()) 的字符分类规则,和来自 std::use_facet<std::numpunct<CharT>>(str.getloc()) 的数值标点字符。此函数为所有有格式输入流运算符,如 std::cin >> n; 所调用。转换分为三个阶段进行:
阶段 1:选择转换说明符
- 获得输入/输出格式标志,如同以
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
- 对于整数类型,在需要时添加长度说明符到转换说明:对于
short和unsigned short是h,对于long和unsigned long是l,对于long long和unsigned long long是ll(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 并不再提取更多字符。 - 如同以
char_type ct = *in;从in提取下个字符:- 如果字符匹配如同用
std::use_facet<std::ctype<CharT>>(str.getloc()).widen()加宽到本地环境的char_type的"0123456789abcdefxABCDEFX+-"(C++11 前)"0123456789abcdepfxABCDEFPX+-"(C++11 起) 字符之一,那么将它转换到对应的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。 - 如果因为测试
in == end而终止阶段 2,那么执行err |= std::ios_base::eofbit设置 eof 位。
返回值
in
注解
在修复 LWG 问题 23 和 LWG 问题 696 前,出现错误时保留 v 不会更改。
在修复 LWG 问题 221 前,因为阶段 2 会过滤掉 'X' 和 'x',所以 do_get(int) 会拒绝表示十六进制整数的字符串(例如 "0xA0"),即使它们是对 strtol 的合法输入。
在修复 LWG 问题 1169 前,转换负整数字符串到无符号整数时,某些实现会产生零(因为字符串所表示的值小于目标类型所能表示的值)。
|
在修复 LWG 问题 2381 前,因为阶段 2 会过滤掉 因为阶段 2 会过滤掉 |
(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 // 设置 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;
}缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 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 | 小数点后的千位分隔符会被忽略 | 碰到它们时终止阶段 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> 的公开成员函数) |