basic_oformatstream 模板类






4.93/5 (4投票s)
旧式 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) const
和 virtual _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);
请注意,formatter
和 oformatstream
是 typedef
,其目的与 cout
和 wcout
的 typedef
类似。如果您想知道,woformatstream
和 wformatter
是宽字符版本。
// 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
可以是 char
或 wchar_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 上提到升级,并希望更新代码以反映所做的努力