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

< 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

- 对于整数类型，若需要则添加长度说明符到转换说明：对于 short 和 unsigned short 为 h ，对于 long 和 unsigned long 为 l ，对于 long long 和 unsigned long long 为 ll
- 若 `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() 加宽到 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 序列为数值

  如同以对有符号整数 `v` 的 std::strtoll 、对无符号整数 `v` 的 std::strtoull 、对 `float` `v` 的 std::strtof 、对 `double` `v` 的 std::strtod 或对 `long double` `v` 的 std::strtold 分析输入

- 若转换函数无法转换整个域，则存储值 ​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`

### 注解

C++98/C++03 指定若出现错误则保留 `v` 不更改。这种行为被并入 C++11 的 LWG23 及 LWG696 更正。

转换负整数字符串为无符号整数时，某些实现产生零（因为字符串所表示的值小于目标类型所能表示的）。这种行为曾被 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` 一致

### 参阅

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