C++ iomanip库的有效使用

2022-01-07 00:00:00 stream iostream c++ iomanip

我用 C++ 创建了一个 Vector 类,它非常适合我的问题.我现在正在清理它,我遇到了以下代码:

I created a Vector class in C++ and it works great for my problems. I am now cleaning it up, and I ran into the following piece of code:

std::ostream& operator<<(std::ostream &output, const Vector &v){
  output<<"["
    <<std::setiosflags(std::ios::right | std::ios::scientific)
    <<std::setw(23)
    <<std::setprecision(16)
    <<v._x<<", "
    <<std::setiosflags(std::ios::right | std::ios::scientific)
    <<std::setw(23)
    <<std::setprecision(16)
    <<v._y<<", "
    <<std::setiosflags(std::ios::right | std::ios::scientific)
    <<std::setw(23)
    <<std::setprecision(16)
    <<v._z<<"]";
  return output;
} 

该代码允许将向量打印为 std::cout<<v<<std::endl;.每个数字有23个空格,其中16个是小数.文本右对齐以便打印:

The code allows to print a vector as std::cout<<v<<std::endl;. Each number has 23 spaces, of which 16 are the decimals. The text is right-aligned so that it will print:

 1.123456123456e+01
-1.123456123456e+01

代替

1.123456123456e+01
-1.123456123456e+01

代码看起来非常重复.您如何存储"格式(所有 setiosflagssetwsetprecision 语句),以便您可以说打印字符以标准方式,但具有这种给定格式的数字".

The code seems awfully repetitive. How can you "store" the format (all the setiosflags, setw and setprecision statements) such that you can say something like "print the characters in a standard way, but the numbers with this given format".

谢谢!

编辑

根据 Rob Adams 的评论,我将丑陋的代码(正如其他人指出的那样,会破坏下一个人"的精确度)更改为更简洁(且正确):

As per Rob Adams' comment, I changed my ugly code (which, as pointed out by others, would mess up the precision for the "next guy") to a more succinct (and correct):

std::ostream& operator<<(std::ostream &output, const Vector &v){
  std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific);
  std::streamsize p = output.precision(16);
  output<<"["
    <<std::setw(23)<<v._x<<", "
    <<std::setw(23)<<v._y<<", "
    <<std::setw(23)<<v._z
    <<"]";
  output.flags(f);
  output.precision(p);
  return output;
}

推荐答案

只有 std::setw() 是临时的.另外两个调用 setiosflagssetprecision 具有永久效果.

Only std::setw() is temporary. The other two calls, setiosflags, and setprecision have a permanent effect.

因此,您可以将代码更改为:

So, you could change your code to :

std::ostream& operator<<(std::ostream &output, const Vector &v){
  output<<"["
    <<std::setiosflags(std::ios::right | std::ios::scientific)
    <<std::setw(23)
    <<std::setprecision(16)
    <<v._x<<", "
    <<std::setw(23)
    <<v._y<<", "
    <<std::setw(23)
    <<v._z<<"]";
  return output;
} 

但现在你已经为下一个家伙浪费了旗帜和精确度.试试这个:

But now you've borked the flags and precision for the next guy. Try this instead:

std::ostream& operator<<(std::ostream &output, const Vector &v){
  std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific);
  std::streamsize p = output.precision(16);
  output<<"["
    <<std::setw(23)
    <<v._x<<", "
    <<std::setw(23)
    <<v._y<<", "
    <<std::setw(23)
    <<v._z<<"]";
  output.flags(f);
  output.precision(p);
  return output;
} 

最后,如果您绝对必须摆脱常量 23 的重复,您可以这样做(但我不推荐这样做):

Finally, if you absolutely have to get rid of the duplication of the constant 23, you could do something like this (but I wouldn't recommend it):

struct width {
  int w;
  width(int w) : w(w) {}
  friend std::ostream& operator<<(std::ostream&os, const width& w) {
    return os << std::setw(width.w);
  }
};


std::ostream& operator<<(std::ostream &output, const Vector &v){
  std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific);
  std::streamsize p = output.precision(16);
  width w(23);
  output<<"["
    <<w
    <<v._x<<", "
    <<w
    <<v._y<<", "
    <<w
    <<v._z<<"]";
  output.flags(f);
  output.precision(p);
  return output;
} 

另请参阅另一个问题,他们认为您不能将宽度设为永久.

See also this other question, where they decided that you can't make width permanent.

相关文章