65.9K
CodeProject 正在变化。 阅读更多。
Home

basic_oformatstream 模板类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (4投票s)

2001 年 11 月 14 日

MIT

4分钟阅读

viewsIcon

58728

downloadIcon

868

旧式 printf 格式字符串移植到 ostream 包装类

引言

我很确定会有人问“你为什么要构建这个?”。是的,它比 printf 慢,并且比 STL wcout 稍大,但是...

除了学习经验之外,我构建这个模板类还有两个主要原因。

一方面,我觉得 STL 的操纵符很麻烦;另一方面,printf 系列函数有一个主要的缺点,它们不允许输出 string 任意增长。

我本可以只包装 ostrstream 类,但这会不必要地限制此模板用于其他类型的输出,即文件和控制台。

主模板类 basic_oformatstream 在用户和它绑定的 ostream 对象之间充当一个“垫片”(“放在两个部分之间以使其契合的薄物体”)。

警告:VC++ 6.0 STL 实现(来自 Dinkumware)中存在一个错误。

有关错误的简短描述(附带代码),请参见文件 oformatstream.cpp 的末尾。初始修复方法是在 <xlocnum> 模板 num_put 函数 virtual _OI do_put(_OI _F, ios_base& _X, _E _Fill, double _V) constvirtual _OI do_put(_OI _F, ios_base& _X, _E _Fill, long double _V) const 中将缓冲区大小设置得更大。如果您对标准模板库文件进行此类更改感到恐惧,我不会责怪您,所以如果您无法或不愿修复此问题,那么永远不要尝试输出一个非常大的浮点值而不使用科学计数法,即 %e%g,而另一个 %f 可能会给您带来麻烦。

那么如何使用它?

首先,通过为其提供格式和要写入的输出流来构造一个 oformatstream。然后,只需将值输出到生成的 oformatstream 即可。您发送输出值的顺序,正如您应该预期的那样,完全取决于您在格式 string 中指定的顺序。

您可以使用 reformat 操纵符来更改格式 string,该操纵符将 basic_formatter 对象作为其参数。

formatter f("%8d %6.2f");
oformatstream ofs("%8x %5.3e",&std::cout);

ofs <<  reformat(f);

请注意,formatteroformatstreamtypedef,其目的与 coutwcouttypedef 类似。如果您想知道,woformatstreamwformatter 是宽字符版本。

// Example usage:
//
// First a really simple situation: 
oformatstream ofs("[%s] [%8d] [%6.5f]\n", &std::cout);
ofs << "example" << 1 << 3.141592 << setformat;

// Note setformat is used to make sure the last field is output.
// The last field ? Yes the "]\n" text.
// You could also drop the '\n' and use the endl inserter instead.
// This would result in the following code.
oformatstream ofs("[%s] [%8d] [%6.5f]", &std::cout);
ofs << "example" << 1 << 3.141592 << setformat << endl;

// A slightly more complex example: 

// Set up a custom default format specification first 
format_specification fs(12 /*width*/,2/*precision*/,std::ios_base::dec); 

// Generate a formatter with this default format specification 
formatter format("[%s] [%d] [%f]", fs);

 // Construct the oformatstream with this custom formatter 
oformatstream ofs(format, &std::cout); 
ofs << "example" << 1 << 3.141592 << endl;

有关一些非常复杂的示例,请参阅演示中的 TestFormat.cpp

以下是对模板类以及您在 oformatstream.hpp 中找到的各种实现类和函数的更详细描述。

basic_oformatstream

构造函数

  • 默认构造函数。需要先调用 tie() 才能进行输出
    basic_oformatstream()
  • 使用格式 string 来构造内部格式字段向量
    basic_oformatstream(const std::basic_string<_E,_Tr>& s, _Myostream *os = NULL)
  • 使用预先构造的 basic_formatter,它允许自定义默认格式规范
    basic_oformatstream(const basic_formatter<_E>& f, _Myostream *os = NULL)

公共方法

  • 插入运算符
    _Myt& operator<<(T) for T= {bool,int,long,...etc.}
  • 设置内部格式化器
    void formatter(constbasic_formatter<_E,_Tr>& f)
  • 返回内部格式化器
    basic_formatter<_E>& formatter()
  • 绑定到输出流
    void tie(_Myostream *os)
  • 返回绑定的输出流
    _Myostream* get_ostream()
  • 设置默认格式规范
    void default_format_specification(const format_specification& f)
  • 返回默认格式规范
    format_specification default_format_specification()

以及其他几个内部使用但需要设为 public 的。

basic_formatter

构造函数

  • 默认构造函数
    basic_formatter()
  • 提供默认格式规范
    basic_formatter(const format_specification fs)
  • 使用格式 string
    basic_formatter(std::basic_string<_E,_Tr> fs)
  • 使用格式 string 并提供默认格式规范
    basic_formatter(std::basic_string<_E,_Tr> s, const format_specification& fs)

实现类

format_flags

管理 std::ios_base::fmtflags 值的更改。强制执行诸如十六进制、十进制和八进制标志互斥之类的限制。提供运算符 |=&== 以及各种构造函数和转换运算符。

format_specification

单个字段的格式规范对应于单个字段,即“%7.5f”。

TEMPLATE CLASS format_characters

为解析例程提供了一个存储常量的中心位置。目前 _E 可以是 charwchar_t

TEMPLATE CLASS basic_formatterfield

保存解析单个字段格式规范的最终结果。这些是前缀文本 string 和字段的格式规范。

TEMPLATE CLASS FormatFieldVector

派生自 std::vector< basic_formatterfield<_E,_Tr>>

解析例程

std::ios_base::fmtflags format_flag_from_char<_E>(const _E ch)

将类型字符 [cdefgisx] 转换为适当的 ios_base 标志值。

bool parse_format_specification<_E>(

std::basic_string<_E>::const_iterator& it,

std::basic_string<_E>::const_iterator& end,

format_specification& outfs, bool& widthset, bool& precset, _E& fillchar)

parse_field<_E>() 调用,用于处理单个字段的格式规范,即百分号(%)符号之后的所有内容。

bool parse_field <_E>(

std::basic_string<_E>::const_iterator& it,

std::basic_string<_E>::const_iterator& end,

basic_formatterfield<_E>& outff,

format_specification& default_fs)

parse_format<_E> 调用,用于处理一个格式字段,即前缀文本后跟一个格式规范。调用 parse_format_specification<_E>()

bool parse_format<_E>(

std::basic_string<_E>fs,

FormatFieldVector<_E>& ffv,

format_specification& default_fs)

basic_formatter<_E> 构造函数用于处理完整的格式规范。调用 parse_field<_E>() 来构建一个 basic_formatterfield,然后将其存储在 FormatFieldVector 中。

格式输出管理类

TEMPLATE CLASS basic_formatter

每个字段的格式由给定的格式 string 控制。

TEMPLATE CLASS basic_oformatstream

将值输出到连接的 stream(如果未连接则什么也不做)。内部 basic_formatter 对象控制每个输出字段的布局以及它们被期望的顺序。如果提供的字段类型与预期格式不匹配,则不会抛出异常。输出可能看起来很难看。

历史

  • 2001年11月14日:首次发布
  • 2022年9月26日:在 Reddit 上提到升级,并希望更新代码以反映所做的努力
© . All rights reserved.