std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::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;
(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;
(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, unsigned 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, 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 序列为数值
如同以对有符号整数 vstd::strtoll 、对无符号整数 vstd::strtoull 、对 float vstd::strtof 、对 double vstd::strtod 或对 long double vstd::strtold 分析输入
  • 若转换函数无法转换整个域,则存储值 0v
  • 若转换函数产生过大而无法适合作为有符号整数类型的 v 类型的正值或负值,则分别存储可表示的最正值或最负值于 v
  • 若转换函数产生不适合作为无符号整数类型的 v 类型的值,则存储可表示的最正值于 v
  • 任何情况下,若转换函数失败,则赋值 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 的 LWG23LWG696 更正。

转换负整数字符串为无符号整数时,某些实现产生零(因为字符串所表示的值小于目标类型所能表示的)。这种行为曾被 C++11/14 标准指定,但被 LWG1169 更正。

因为阶段 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;
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
LWG 23 C++98 溢出的输入导致未定义行为 处理溢出
LWG 696 C++98 转换失败时不更改结果 设为零
LWG 1169 C++98 溢出处理在不同浮点类型间不一致 使得与 strtof/strtod 一致

参阅

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