名稱空間
變體
操作

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

來自 cppreference.com
< cpp‎ | locale‎ | num get
 
 
 
 
std::num_get
成員函式
num_get::getnum_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;
(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 型別的值,同時考慮來自 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 表示 shortunsigned shortl 表示 longunsigned longll 表示 long longunsigned long long(C++11 起)
  • 如果 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() 獲取的字元序列進行匹配,僅在必要時才進行唯一匹配。輸入迭代器 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 是否允許在給定階段 1 中選擇的轉換說明符的情況下由 std::scanf 解析的輸入欄位中。如果允許,則將其累積到臨時緩衝區中,並重復階段 2。如果不允許,則階段 2 終止。

[編輯] 階段 3:轉換和儲存

  • 階段 2 中累積的 char 序列被轉換為數值
輸入根據 std::scanf 的規則進行解析。
(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 23LWG issue 696 解決之前,如果發生錯誤,v 保持不變。

LWG issue 221 解決之前,表示十六進位制整數的字串(例如 "0xA0")會被 do_get(int) 拒絕,即使它們是 strtol 的有效輸入,因為階段 2 會過濾掉字元 'X''x'

LWG issue 1169 解決之前,將負數字符串轉換為無符號整數可能會產生零(因為字串表示的值小於目標型別可以表示的值)。

LWG issue 2381 解決之前,表示帶指數的十六進位制浮點數(例如 "0x1.23p-10")的字串會被 do_get(double) 拒絕,即使它們是 strtod 的有效輸入,因為階段 2 會過濾掉字元 'P''p'

表示無窮大或非數字的字串(例如 "NaN""inf")會被 do_get(double) 拒絕,即使它們是 strtod 的有效輸入,因為階段 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 小數點後的千位分隔符被忽略 如果遇到,階段 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> 的公有成員函式) [編輯]