std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put
来自 cppreference.cn
定义于头文件 <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; |
(since 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; |
(since 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; |
(since 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; |
(since 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 facets 进行格式化。此函数由所有格式化输出流运算符调用,例如 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,则获取 std::use_facet<std::numpunct<CharT>>(str.getloc()).truename() (如果 val == true)或 std::use_facet<std::numpunct<CharT>>(str.getloc()).falsename() (如果 val == false),并将该字符串的每个后续字符 c 输出到 out,使用 *out++ = c。在这种情况下,不再进行进一步处理,函数返回 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) |
|
(since C++11) |
- 如果 floatfield == std::ios_base::scientific && !uppercase,将使用转换说明符 %e。
- 如果 floatfield == std::ios_base::scientific,将使用转换说明符 %E。
|
(since 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 的组合产生)不计为填充字符。
当将浮点值格式化为 hexfloat 时(即,当 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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
LWG 34 | C++98 | bool 重载使用了不存在的成员 truename 和 falsename of std::ctype |
使用这些成员 of std::numpunct |
LWG 231 | C++98 | 仅当以下情况时才添加精度修饰符 (flags & fixed) != 0 or str.precision() > 0 |
移除了这些条件 |
LWG 282 | C++98 | 千位分隔符仅 在阶段 2 中为整数类型插入 |
也为以下类型插入 浮点类型 |
LWG 4084 | C++11 | "NAN" 和 "INF" 无法打印 | 它们可以被打印 |
[编辑] 参见
插入格式化数据 ( std::basic_ostream<CharT,Traits> 的公有成员函数) |