10

假设我有一个函数,它接受一个ostream &参数o并写入该 ostream。一个operator <<实现将是一个很好的例子。

ostream& operator << (ostream& o, const MyThing& t)
{
  // ... interesting code here ...
  return o;
}

在函数中,我可能想在流上指定格式选项。例如,我可能希望将一个数字打印为十六进制,无论o它在传递给函数时是如何配置的。

其次,我可能希望能够对当前的格式化标志做出假设。例如,除非我另有要求,否则能够假设数字被格式化为十进制会很好。

最后,当函数退出时,我希望格式化选项o与调用函数之前的格式选项相同,以便对调用者保持不变。这只是对呼叫者的礼貌问题。

到目前为止,我已经通过ostringstream在函数中创建一个 local 来实现这一点,完成我所有的工作(包括设置格式选项),并在函数末尾 发送.str()to 。这里的 StackOverflow 问题表明比我聪明的人也采用相同的方法。 但是,让我感到困扰的是,我在 ostringstreams 中保留了这么多数据,这些数据可能会更早地发送到输出(字符串可能会变得非常大)。o

我有两个问题:

1)创建一个临时的(基于堆栈的)ostream并在该ostream 上做我的工作是否合法、惯用、良好的形式等?o.rdbuf()我自己的测试和cppreference.com上的页面似乎表明我可以。

ostream& operator << (ostream& o_, const MyThing& t)
{
  ostream o (o_.rdbuf());
  // write stuff to "o",
  // setting formatting options as I go.
  return o_; // Formatting on the parameter ostream o_ unchanged.
}

2)我没有考虑过另一种更好的方法吗?

4

3 回答 3

2

Boost IO State Savers正是为此目的而构建的。

于 2014-11-06T12:07:34.867 回答
1

这不是一个糟糕的解决方案。这当然是合法的。我认为这不太常见,所以评论一下你为什么这样做可能是个好主意。

我在这里看到的最常见的解决方案是创建一个状态保存程序类,它将在构造函数中保存您需要的所有状态(通常是flags(),precision()fill()),并在析构函数中恢复它,然后强制设置所有您想要的选项。(也许可以使用copyfmt它,尽管这也复制了异常掩码之类的东西,你可能不想玩。)

于 2014-11-06T12:23:57.280 回答
0

这些设置可以存储在一种称为 fmtflags 对象的对象中,该对象定义在一个名为 ios 的类中,该类包含在 iostream 中。您可以声明这些对象之一,但您必须使用范围解析运算符来声明它。

以下语句将在变量 old_settings 中保存格式状态的某些方面:

ios::fmtflags old_settings = cout.flags();

然后,在使用新设置进行输出后,您可以通过使用旧设置作为参数调用相同的函数来恢复旧设置:

cout.flags(old_settings);

其他设置可以通过成员函数获取和恢复。例如,

int old_precision = cout.precision();

将保存当前精度规范。然后

cout.precision(old_precision);

将精度恢复到原始值

于 2014-11-06T12:07:22.253 回答