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

时间:2016-02-09 06:40:52

标签: c++ iostream c++-standard-library

我觉得我在问一个非常基本的问题,但我还没有在这里或谷歌找到答案。我记得我们在学校教过这个,但是它已经消失多年了。

为什么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

此&#34;实施是否具体/未由标准定义&#34;? 请随意将其标记为重复,因为我无法在SO上找到它。

2 个答案:

答案 0 :(得分:5)

未指定函数参数评估的顺序。当您致电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)创建的临时值就会被创建。然后在调用适当的移位运算符时应用效果。由于必须以适当的顺序调用移位运算符,因此操纵器的使用发生在已知的位置。

答案 1 :(得分:4)

未定义第一个示例中评估cout.precision(3)的确切时间,因为其值用作函数调用的参数。 OTOH与第二个例子一样,setprecision(3)被插入到流中的时间被很好地定义 - 即在插入endl之后和test之前(第二次)。因此,第一个版本不会产生可靠的结果(你得到的结果可能会因不同的实现而有所不同),但第二个版本将会出现。

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