我觉得我在问一个非常基本的问题,但我还没有在这里或谷歌找到答案。我记得我们在学校教过这个,但是它已经消失多年了。
为什么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上找到它。
答案 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。 (那里的问题没有使用运算符,但原理是相同的 - 在另一个函数的返回值上调用成员函数。)