std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get
來自 cppreference.com
(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 是否允許在給定階段 1 中選擇的轉換說明符的情況下由 std::scanf 解析的輸入欄位中。如果允許,則將其累積到臨時緩衝區中,並重復階段 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")會被 do_get(int)
拒絕,即使它們是 strtol 的有效輸入,因為階段 2 會過濾掉字元 'X' 和 'x'。
在 LWG issue 1169 解決之前,將負數字符串轉換為無符號整數可能會產生零(因為字串表示的值小於目標型別可以表示的值)。
在 LWG issue 2381 解決之前,表示帶指數的十六進位制浮點數(例如 "0x1.23p-10")的字串會被 表示無窮大或非數字的字串(例如 "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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
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> 的公有成員函式) |