命名空间
变体
操作

std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put

来自 cppreference.com
< cpp‎ | locale‎ | num put
 
 
 
std::num_put
成员函数
num_put::putnum_put::do_put
 
定义在头文件 <locale>
(1)
public:

iter_type put( iter_type out, std::ios_base& str,

               char_type fill, bool val ) const;
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,

                          char_type fill, bool val ) const;
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) 将表示 val 值的字符写入输出序列 out,格式如格式化标志 str.flags() 和流 str 中注入的区域设置的 std::numpunctstd::ctype 方面所请求的那样。此函数由所有格式化的输出流运算符调用,例如 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,并使用 *out++ = c 将该字符串中的每个后续字符 c 输出到 out。在这种情况下,不会进行进一步处理,函数将返回 out
  • 如果 val 的类型是整数类型,则选择以下第一个适用的选项
    • 如果 basefield == oct,则使用转换说明符 %o
    • 如果 basefield == hex && !uppercase,则使用转换说明符 %x
    • 如果 basefield == hex,则使用转换说明符 %X
    • 如果 val 的类型是有符号的,则使用转换说明符 %d
    • 如果 val 的类型是无符号的,则使用转换说明符 %u
  • 对于整数类型,如果需要,则在转换说明符中添加长度修饰符:l 用于 longunsigned long, ll 用于 long longunsigned long long(自 C++11 起).
  • 如果 val 的类型是浮点类型,则选择以下第一个适用的选项
(自 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 是选定的转换说明符。

[edit] 第 2 阶段:区域设置特定转换

[edit] 第 3 阶段:填充

  • 调整标志获得的方式如同通过 std::fmtflags adjustfield = (flags & (std::ios_base::adjustfield)) 获得并检查以确定填充位置,如下所示
  • 如果 str.width() 不为零(例如,刚刚使用了 std::setw)并且阶段 2 之后的 CharT 数量少于 str.width(),则将 fill 字符的副本插入填充指示的位置,以使序列长度达到 str.width()

在任何情况下,都会调用 str.width(0) 以取消 std::setw 的影响。

[edit] 阶段 4:输出

从阶段 3 的 CharT 序列中输出每个连续的字符 c,就好像通过 *out++ = c 一样。

[edit] 参数

out - 指向要覆盖的第一个字符的迭代器
str - 用于检索格式信息的流
fill - 当结果需要填充到字段宽度时使用的填充字符
val - 要转换为字符串并输出的值

[edit] 返回值

out

[edit] 注释

由转换说明符 #o 生成的前导零(例如,由 std::showbasestd::oct 的组合产生)不被视为填充字符。

当将浮点值格式化为十六进制浮点数(即,当 floatfield == (std::ios_base::fixed | std::ios_base::scientific))时,不会使用流的精度;相反,始终以足够的精度打印数字以精确地表示该值。

(自 C++11 起)

[edit] 示例

使用面直接输出一个数字,并演示用户定义的面

#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, 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 (...)
    {
        // set badbit on os and rethrow if required
    }
 
    return os;
}
 
int main()
{
    base b;
    std::cout << b;
}

输出

10

[edit] 缺陷报告

以下行为更改缺陷报告被追溯地应用于先前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
LWG 34 C++98 所使用的 bool 重载使用不存在的成员
truenamefalsenamestd::ctype
使用 std::numpunct 的这些成员
LWG 231 C++98 仅在
(flags & fixed) != 0str.precision() > 0 时添加精度修饰符
删除了这些条件
LWG 282 C++98 千位分隔符仅在阶段 2 中为整数类型插入 也为浮点数类型插入

[edit] 另请参阅

插入格式化的数据
(std::basic_ostream<CharT,Traits> 的公共成员函数) [edit]