std::num_put<CharT,OutputIt>:: put, std::num_put<CharT,OutputIt>:: do_put
|
定义于头文件
<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 ; |
||
do_put
。
转换发生在四个阶段:
目录 |
阶段 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 ( ) ,并将该字符串的每个连续字符 c 通过 * out ++ = 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 ) ),流对象的精度设置不会被使用;取而代之的是,数值总是以能够精确表示该值所需的足够精度进行输出。 |
(since C++11) |
示例
直接使用facet输出数字,并演示用户自定义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>
的公开成员函数)
|