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

< cpp‎ | locale‎ | num put

定义于头文件 `<locale>` |  |
| (1) |
public: iter_type put( iter_type out, std::ios_base& str, char_type fill, bool v ) const; |  |
iter_type put( iter_type out, std::ios_base& str, char_type fill, long v ) const; |  |
iter_type put( iter_type out, std::ios_base& str, char_type fill, long long v ) const; |  | (C++11 起)
iter_type put( iter_type out, std::ios_base& str, char_type fill, unsigned long v ) const; |  |
iter_type put( iter_type out, std::ios_base& str, char_type fill, unsigned long long v ) const; |  | (C++11 起)
iter_type put( iter_type out, std::ios_base& str, char_type fill, double v ) const; |  |
iter_type put( iter_type out, std::ios_base& str, char_type fill, long double v ) const; |  |
iter_type put( iter_type out, std::ios_base& str, char_type fill, const void* v ) const; |  |
| (2) |
protected: virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, bool v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long long v ) const; |  | (C++11 起)
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, unsigned long v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, unsigned long long v ) const; |  | (C++11 起)
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, double v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, long double v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, const void* v ) const; |  |

1) 公开成员函数，调用最终导出类的受保护虚成员函数 `do_put` 。
2) 写字符到输出序列 `out` ，这些字符表示 `v` 的值，按格式化标志 str.flags() 和流 `str` 中感染的 locale 的 std::numpunct 和 std::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);

- 若 `v` 的类型为 bool
  - 若 boolalpha == 0 ，则转换 `v` 为 int 类型并进行整数输出。
  - 若 boolalpha != 0 ，则若 v == 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` 。
- 若 `v` 的类型为整数类型，则选择下列首个可应用选项：

  若 basefield == oct ，则将使用转换说明符 %o
  若 basefield == hex && !uppercase ，则将使用转换说明符 %x
  若 basefield == hex ，则将使用转换说明符 %X
  若 `v` 的类型有符号，则将使用转换说明符 %d
  若 `v` 的类型无符号，则将使用转换说明符 %u

- 对于整数类型，若需要则添加长度修饰符到转换说明：对于 long 和 unsigned long 为 l ，对于 long long 和 unsigned long long 为 ll 。
- 若 `v` 为浮点类型，则选择首个可应用选项：

  若 floatfield == std::ios_base::fixed ，则将使用转换说明符 %f
  若 floatfield == std::ios_base::scientific && !uppercase ，则将使用转换说明符 %e
  若 floatfield == std::ios_base::scientific ，则将使用转换说明符 %E

若 floatfield == (std::ios_base::fixed | std::ios_base::scientific) && !uppercase ，则将使用转换说明符 %a 若 floatfield == (std::ios_base::fixed | std::ios_base::scientific) ，则将使用转换说明符 %A | (C++11 起)

  若 !uppercase ，则将使用转换说明符 %g
  否则，将使用转换说明符 %G
  - 若 `v` 的类型为 long double ，则添加长度修饰符 L 到转换说明符。
  - 另外若 floatfield != (ios_base::fixed | ios_base::scientific) 则 (C++11 起)添加设为 str.precision() 的精度说明符

- 对于整数和浮点类型，若设置了 showpos ，则前附修饰符 + 。
- 对于整数类型，若设置了 showbase ，则前附修饰符 # 。
- 对于浮点类型，若设置了 showpoint ，则前附修饰符 # 。
- 若 `v` 的类型为 void* ，则将使用格式说明符 %p 。
- 如同以在 "C" 本地环境中调用 std::printf(spec, v) 创建窄字符串，其中 `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 | - | 需要填充结果到域宽时使用的填充字符
v | - | 转换为字符串并输出的值

### 返回值

`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 s, std::ios_base& f,
                         char_type fill, long v) const
        {
            return std::num_put<char>::do_put(s, f, fill, v*v );
        }

        iter_type do_put(iter_type s, std::ios_base& f,
                         char_type fill, unsigned long v) const
        {
            return std::num_put<char>::do_put(s, f, fill, v*v);
        }
    };

    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

### 参阅

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