std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put
来自cppreference.com
| 在标头 <locale> 定义
|
||
| (1) | ||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
| (2) | ||
| |
||
| |
||
| |
(C++11 起) | |
| |
||
| |
(C++11 起) | |
| |
||
| |
||
| |
||
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是浮点数类型,那么选择下列首个可应用选项:
|
(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:本地环境限定转换
- 调用
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 时(即 |
(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, 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 (...)
{
// 设置 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 中只会对整数类型插入千位分隔符 | 对浮点数类型也会 |
| LWG 4084 | C++11 | 无法打印 "NAN" 和 "INF"
|
可以打印 |
参阅
| 插入带格式数据 ( std::basic_ostream<CharT,Traits> 的公开成员函数) |