为什么 cout.precision() 会影响整个流

Why does cout.precision() affect the whole stream?

本文关键字:影响 cout precision 为什么      更新时间:2023-10-16

我觉得我在问一个非常基本的问题,但我无法在这里或谷歌中找到答案。我记得我们在学校被教导过这个,但可惜它已经消失了多年。

为什么在输出列表中间调用cout.precision()std::ios_base::precision())会影响整个流?我知道应该使用 std::setprecision() 来动态更改精度的规则,并且cout.precision()会用它返回的值破坏输出。但这有什么机制呢?是由于缓冲吗?手册中指出这些"做同样的事情",但从经验上看,我可以看到这并不完全正确。

MCVE:

const double test = 1.2345;
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);
cout << test << endl << cout.precision(3) <<  test << endl;
// Output:
// 1.234
// 21.234
// after the same init
cout.precision(2);
cout << test << endl << setprecision(3) <<  test << endl;
// Output
// 1.23
// 1.234

这是"特定于实施/未由标准定义"吗?随意将其标记为重复,因为我无法在SO上找到它。

未指定函数参数求值的顺序。调用std::cout.precision(n)时,std::cout ' 的精度是在计算此调用时设置的。在你的表达中

cout << test << endl << cout.precision(3) <<  test << endl;

显然,cout.precision(3)被称为编译器完全允许做的第一件事。 请记住,编译器认为上述语句等效于

std::cout.operator<<(test)
          .operator<<(std::endl)
          .operator<<(std::cout.preision(3))
          .operator<<(test)
          .operator<< (std::endl);

实际上,您的编译器函数参数似乎是从右到左计算的。只有这样,才会执行不同的班次运算符。结果,精度在输出完成之前发生变化。

使用像std::setprecision(n)这样的操纵器避免了依赖顺序子表达式被评估:从std::setprecision(n)创建的临时创建无论何时创建。然后,在调用相应的移位运算符时应用该效果。由于必须按适当的顺序调用换档操作员,因此机械手的使用发生在已知位置。

第一个示例中计算cout.precision(3)的确切时间尚未定义,因为它的值用作函数调用的参数。OTOH 在第二个示例中,setprecision(3)插入流的时间定义得非常好 - 即插入endl之后和test之前(第二次)。因此,第一个版本不会产生可靠的结果(在不同的实现上,你得到的结果可能不同),但第二个版本会。

有关更详细的解释,请参阅此问题。(那里的问题没有使用运算符,但原理是相同的 - 在另一个函数的返回值上调用一个成员函数。