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 平面所要求者格式化。此函数会被所有有格式输出流运算符,如 std::cout << n; 调用。
转换以四个阶段发生:
阶段 1:转换说明符选择
- 获得输入/输出格式标志,如同以
- 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(),或者在 v == 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
- 对于整数类型,在有需要时添加长度修饰符到转换说明:对于 long 和 unsigned long 是 l,对于 long long 和 unsigned long long 是 ll (C++11 起)。
- 如果 val 是浮点类型,那么选择下列首个可应用选项:
- 如果 floatfield == std::ios_base::fixed,那么会使用转换说明符 %f
- 如果 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:本地环境限定转换
- 调用 std::use_facet<std::ctype<CharT>>(str.getloc()).widen(c),将阶段 1 中获得的每个小数点 '.' 以外的字符 c 转换到 CharT。
- 对于算术类型,按照 std::use_facet<std::numpunct<CharT>>(str.getloc()).grouping() 提供的分组规则,插入从 std::use_facet<std::numpunct<CharT>>(str.getloc()).thousands_sep() 获得的千位分隔字符到序列中。
- 以 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:输出
如同用 *out++ = c 输出来自阶段 3 的 CharT 序列的每个相继字符 c。
参数
out | - | 指向首个要写入字符的迭代器 |
str | - | 取得格式化信息来源的流 |
fill | - | 需要填充结果到域宽时使用的填充字符 |
val | - | 转换为字符串并输出的值 |
返回值
out
注解
转换说明 #o (例如产生自 std::showbase 和 std::oct 的组合)不计为填充字符。
格式化浮点值是 hexfloat 时(即 floatfield == (std::ios_base::fixed | std::ios_base::scientific) 时),不使用流的精度;而是始终以足以准确表示值的精度打印该数。 |
(C++11 起) |
示例
用平面直接输出数,并演示用户定义的平面:
运行此代码
#include <iostream> #include <locale> // 此定制 num_put 平面输出所有整数类型的平方(除了 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, base const& 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 (...) { // 设置 os 上的 badbit ,而且在需要时重新抛出 } return os; } int main() { base b; std::cout << b; }
输出:
10
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
LWG 34 | C++98 | bool 重载使用了 std::ctype 的不存在的成员 truename 和 falsename | 使用 std::numpunct 的这些成员 |
LWG 231 | C++98 | 只有在 (flags & fixed) != 0 或 str.precision() > 0 时才会添加精度说明符 | 移除这些条件 |
LWG 282 | C++98 | 阶段 2 中只会对整数类型插入千位分隔符 | 对浮点类型也会 |
参阅
插入带格式数据 ( std::basic_ostream<CharT,Traits> 的公开成员函数) |