std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put
來自 cppreference.com
定義於標頭檔案 <locale> |
||
(1) | ||
public: iter_type put( iter_type out, std::ios_base& str, |
||
iter_type put( iter_type out, std::ios_base& str, char_type fill, long val ) const; |
||
iter_type put( iter_type out, std::ios_base& str, char_type fill, long long val ) const; |
(C++11 起) | |
iter_type put( iter_type out, std::ios_base& str, char_type fill, unsigned long val ) const; |
||
iter_type put( iter_type out, std::ios_base& str, char_type fill, unsigned long long val ) const; |
(C++11 起) | |
iter_type put( iter_type out, std::ios_base& str, char_type fill, double val ) const; |
||
iter_type put( iter_type out, std::ios_base& str, char_type fill, long double val ) const; |
||
iter_type put( iter_type out, std::ios_base& str, char_type fill, const void* val ) const; |
||
(2) | ||
protected: virtual iter_type do_put( iter_type out, std::ios_base& str, |
||
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long val ) const; |
||
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long long val ) const; |
(C++11 起) | |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, unsigned long val ) const; |
||
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, unsigned long long val ) const; |
(C++11 起) | |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, double val ) const; |
||
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long double val ) const; |
||
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, const void* val ) const; |
||
1) 公有成員函式,呼叫最派生類的受保護虛成員函式
do_put
。2) 將字元寫入輸出序列 out,這些字元表示 val 的值,根據格式化標誌 str.flags() 以及流 str 中所注入區域設定的 std::numpunct 和 std::ctype 方面(facet)所請求的格式進行格式化。所有格式化輸出流運算子都會呼叫此函式,例如 std::cout << n;。
轉換分四個階段進行
目錄 |
[編輯] 階段 1:轉換說明符選擇
- 獲取 I/O 格式標誌,如同透過以下方式:
- fmtflags basefield = (str.flags() & std::ios_base::basefield);
- fmtflags uppercase = (str.flags() & std::ios_base::uppercase);
- fmtflags floatfield = (str.flags() & std::ios_base::floatfield);
- fmtflags showpos = (str.flags() & std::ios_base::showpos);
- fmtflags showbase = (str.flags() & std::ios_base::showbase);
- fmtflags showpoint = (str.flags() & std::ios_base::showpoint);
- 若 val 的型別為 bool
- 若 boolalpha == 0,則將 val 轉換為 int 型別並執行整數輸出。
- 若 boolalpha != 0,若 val == true 則獲取 std::use_facet<std::numpunct<CharT>>(str.getloc()).truename(),若 val == false 則獲取 std::use_facet<std::numpunct<CharT>>(str.getloc()).falsename(),並按 *out++ = c 將該字串的每個連續字元 c 輸出到 out。在此情況下不再進行進一步處理,函式返回 out。
- 若 val 的型別為整數型別,則選擇以下第一個適用的選項
- 若 basefield == oct,將使用轉換說明符 %o。
- 若 basefield == hex && !uppercase,將使用轉換說明符 %x。
- 若 basefield == hex,將使用轉換說明符 %X。
- 若 val 的型別為有符號,將使用轉換說明符 %d。
- 若 val 的型別為無符號,將使用轉換說明符 %u。
- 對於整數型別,必要時會向轉換說明新增長度修飾符:l 用於 long 和 unsigned long,ll 用於 long long 和 unsigned long long(C++11 起)。
- 若 val 的型別為浮點型別,則選擇以下第一個適用的選項
|
(C++11 前) |
|
(C++11 起) |
- 若 floatfield == std::ios_base::scientific && !uppercase,將使用轉換說明符 %e。
- 若 floatfield == std::ios_base::scientific,將使用轉換說明符 %E。
|
(C++11 起) |
- 若 !uppercase,將使用轉換說明符 %g。
- 否則,將使用轉換說明符 %G。
- 此外
- 若 val 的型別為 long double,則將長度修飾符 L 新增到轉換說明符。
- 若 val 的型別為浮點型別 且 floatfield != (ios_base::fixed | ios_base::scientific)(C++11 起),則新增精度修飾符並設定為 str.precision()。否則,不指定精度。
- 對於整數和浮點型別,若設定了 showpos,則預置修飾符 +。
- 對於整數型別,若設定了 showbase,則預置修飾符 #。
- 對於浮點型別,若設定了 showpoint,則預置修飾符 #。
- 若 val 的型別為 void*,將使用轉換說明符 %p
- 將建立一個窄字元字串,如同透過在 "C" 區域設定中呼叫 std::printf(spec, val),其中 spec 是所選的轉換說明符。
[編輯] 階段 2:區域設定特定轉換
- 在階段 1 中獲取的每個字元 c,除了小數點 '.',都透過呼叫 std::use_facet<std::ctype<CharT>>(str.getloc()).widen(c) 轉換為
CharT
。 - 對於算術型別,從 std::use_facet<std::numpunct<CharT>>(str.getloc()).thousands_sep() 獲取的千位分隔符字元,將根據 std::use_facet<std::numpunct<CharT>>(str.getloc()).grouping() 提供的分組規則插入到序列中。
- 小數點字元 ('.') 將被 std::use_facet<std::numpunct<CharT>>(str.getloc()).decimal_point() 替換。
[編輯] 階段 3:填充
- 調整標誌透過 std::fmtflags adjustfield = (flags & (std::ios_base::adjustfield)) 獲取並檢查以確定填充位置,如下所示
- 若 adjustfield == std::ios_base::left,將在後面填充。
- 若 adjustfield == std::ios_base::right,將在前面填充。
- 若 adjustfield == std::ios_base::internal 且表示中出現符號字元,將在符號後填充。
- 若 adjustfield == std::ios_base::internal 且階段 1 表示以 0x 或 0X 開頭,將在 x 或 X 後填充。
- 否則,將在前面填充。
- 若 str.width() 非零(例如剛使用了 std::setw)且階段 2 後
CharT
的數量小於 str.width(),則將 fill 字元的副本插入到填充指定的位置,以使序列長度達到 str.width()。
無論如何,都呼叫 str.width(0) 以取消 std::setw 的效果。
[編輯] 階段 4:輸出
階段 3 的 CharT
序列中的每個連續字元 c 都透過 *out++ = c 輸出。
[編輯] 引數
out | - | 指向要覆蓋的第一個字元的迭代器 |
str | - | 從中檢索格式化資訊的流 |
fill | - | 當結果需要填充到欄位寬度時使用的填充字元 |
val | - | 要轉換為字串並輸出的值 |
[編輯] 返回值
out
[編輯] 注意
轉換說明符 #o 生成的前導零(例如由 std::showbase 和 std::oct 組合產生)不計為填充字元。
當將浮點值格式化為十六進位制浮點(即當 floatfield == (std::ios_base::fixed | std::ios_base::scientific))時,不使用流的精度;相反,始終以足夠的精度列印數字以精確表示該值。 |
(C++11 起) |
[編輯] 示例
使用方面(facet)直接輸出數字,並演示使用者定義的方面
執行此程式碼
#include <iostream> #include <locale> // this custom num_put outputs squares of all integers (except long long) struct squaring_num_put : std::num_put<char> { iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long val) const { return std::num_put<char>::do_put(out, str, fill, val * val); } iter_type do_put(iter_type out, std::ios_base& str, char_type fill, unsigned long val) const { return std::num_put<char>::do_put(out, str, fill, val * val); } }; int main() { auto& facet = std::use_facet<std::num_put<char>>(std::locale()); facet.put(std::cout, std::cout, '0', 2.71); std::cout << '\n'; std::cout.imbue(std::locale(std::cout.getloc(), new squaring_num_put)); std::cout << 6 << ' ' << -12 << '\n'; }
輸出
2.71 36 144
使用者定義型別的 operator<< 實現。
執行此程式碼
#include <iostream> #include <iterator> #include <locale> struct base { long x = 10; }; template<class CharT, class Traits> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const base& b) { try { typename std::basic_ostream<CharT, Traits>::sentry s(os); if (s) { std::ostreambuf_iterator<CharT, Traits> it(os); std::use_facet<std::num_put<CharT>>(os.getloc()) .put(it, os, os.fill(), b.x); } } catch (...) { // set badbit on os and rethrow if required } return os; } int main() { base b; std::cout << b; }
輸出
10
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 34 | C++98 | bool 過載使用了不存在的成員 truename 和 falsename 的 std::ctype |
使用這些成員 的 std::numpunct |
LWG 231 | C++98 | 精度修飾符僅在以下情況新增 (flags & fixed) != 0 或 str.precision() > 0 |
刪除了這些條件 |
LWG 282 | C++98 | 千位分隔符僅在以下情況新增 階段 2 中用於整數型別 |
也插入用於 浮點型別 |
LWG 4084 | C++11 | 無法列印 "NAN" 和 "INF" | 它們可以列印 |
[編輯] 另見
插入格式化資料 ( std::basic_ostream<CharT,Traits> 的公有成員函式) |