为什么 cout.precision() 会影响整个流?
Why does cout.precision() affect the whole stream?
我觉得我问的是一个非常基本的问题,但我无法在这里或 Google 中找到答案。我记得我们在学校教过这个,但可惜它已经消失多年了。
为什么在输出列表中间调用cout.precision()
(std::ios_base::precision()
)会影响整个流?我知道应该使用 std::setprecision()
来动态更改精度的规则,并且 cout.precision()
会破坏其值为 returns 的输出。但这是什么机制呢?是缓冲的原因吗?手册说明了这些 "do the same thing",但根据经验我可以看出这并不完全正确。
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
这是"implementation specific / not defined by the standard"吗?
请随意将其标记为重复,因为我无法在 SO 上找到它。
在您的第一个示例中计算 cout.precision(3)
的确切时间未定义,因为它的值用作函数调用的参数。 OTOH 对于第二个示例,setprecision(3)
插入流的时间定义非常明确 - 即在插入 endl
之后和 test
之前(第二次)。因此第一个版本不会产生可靠的结果(你得到的结果在不同的实现上可能会有所不同),但第二个版本会。
有关更详细的说明,请参阅 this question。 (那里的问题不使用运算符,但原理是相同的 - 在另一个函数的 return 值上调用成员函数。)
未指定函数参数评估的顺序。当您调用 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)
创建的临时对象会在任何时候创建。然后在调用适当的移位运算符时应用效果。由于必须以适当的顺序调用移位运算符,因此操纵器的使用发生在已知位置。
我觉得我问的是一个非常基本的问题,但我无法在这里或 Google 中找到答案。我记得我们在学校教过这个,但可惜它已经消失多年了。
为什么在输出列表中间调用cout.precision()
(std::ios_base::precision()
)会影响整个流?我知道应该使用 std::setprecision()
来动态更改精度的规则,并且 cout.precision()
会破坏其值为 returns 的输出。但这是什么机制呢?是缓冲的原因吗?手册说明了这些 "do the same thing",但根据经验我可以看出这并不完全正确。
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
这是"implementation specific / not defined by the standard"吗? 请随意将其标记为重复,因为我无法在 SO 上找到它。
在您的第一个示例中计算 cout.precision(3)
的确切时间未定义,因为它的值用作函数调用的参数。 OTOH 对于第二个示例,setprecision(3)
插入流的时间定义非常明确 - 即在插入 endl
之后和 test
之前(第二次)。因此第一个版本不会产生可靠的结果(你得到的结果在不同的实现上可能会有所不同),但第二个版本会。
有关更详细的说明,请参阅 this question。 (那里的问题不使用运算符,但原理是相同的 - 在另一个函数的 return 值上调用成员函数。)
未指定函数参数评估的顺序。当您调用 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)
创建的临时对象会在任何时候创建。然后在调用适当的移位运算符时应用效果。由于必须以适当的顺序调用移位运算符,因此操纵器的使用发生在已知位置。