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

来自cppreference.com
< cpp‎ | locale‎ | num 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) 写字符到输出序列 out ,这些字符表示 val 的值,按格式化标志 str.flags() 和流 str 中浸染的本地环境的 std::numpunctstd::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 输出该字符串的每个相继字符 cout。此时不进行进一步的操作,函数返回 out
  • 如果 val 的类型是整数类型,那么选择下列首个可应用选项:
    • 如果 basefield == oct,那么会使用转换说明符 %o
    • 如果 basefield == hex && !uppercase,那么会使用转换说明符 %x
    • 如果 basefield == hex,那么会使用转换说明符 %X
    • 如果 val 的类型有符号,那么会使用转换说明符 %d
    • 如果 val 的类型无符号,那么会使用转换说明符 %u
  • 对于整数类型,在有需要时添加长度修饰符到转换说明:对于 longunsigned longl,对于 long longunsigned long longll (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 是所选的格式说明符。

阶段 2:本地环境限定转换

阶段 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 的效果。

阶段 4:输出

如同用 *out++ = c 输出来自阶段 3 的 CharT 序列的每个相继字符 c

参数

out - 指向首个要写入字符的迭代器
str - 取得格式化信息来源的流
fill - 需要填充结果到域宽时使用的填充字符
val - 转换为字符串并输出的值

返回值

out

注解

转换说明 #o (例如产生自 std::showbasestd::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 的不存在的成员 truenamefalsename 使用 std::numpunct 的这些成员
LWG 231 C++98 只有在 (flags & fixed) != 0str.precision() > 0 时才会添加精度说明符 移除这些条件
LWG 282 C++98 阶段 2 中只会对整数类型插入千位分隔符 对浮点类型也会

参阅

插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)