问题
I feel I'm asking a very basic question, but I haven't been able to find an answer here or in Google. I recall we were taught this at school, but alas it has vanished over years.
Why does cout.precision()
(std::ios_base::precision()
) affect the whole stream when called in the middle of the output list? I know the rule that std::setprecision()
should be used to change precision on the fly, and that cout.precision()
is going to spoil the output with the value it returns. But what is the mechanics of this? Is it due to buffering? The manuals state these "do the same thing", but empirically I can see it's not entirely true.
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
Is this "implementation specific / not defined by the standard"? Feel free to mark this as duplicate, for I haven't been able to find it on SO.
回答1:
The order of function argument evaluation is unspecified. When you call std::cout.precision(n)
the precision of std::cout
' is set at the point this call is evaluated. In your expression
cout << test << endl << cout.precision(3) << test << endl;
the cout.precision(3)
is, apparently, called first thing which the compiler is entirely allowed to do. Remember that the compiler considers the above statement equivalent to
std::cout.operator<<(test)
.operator<<(std::endl)
.operator<<(std::cout.preision(3))
.operator<<(test)
.operator<< (std::endl);
Practically, it seems for your compiler function arguments are evaluated right to left. Only then the different shift operators are executed. As a result, the precision gets changed before the output is done.
The use of manipulators like std::setprecision(n)
avoids relying on the order subexpressions are evaluated: the temporary created from std::setprecision(n)
is created whenever it is. The effect is then applied when the appropriate shift operator is called. Since the shift operators have to be called in the appropriate order, the use of the manipulator happens at a known place.
回答2:
The exact time when cout.precision(3)
is evaluated in your first example is not defined, because its value serves as an argument for a function call. OTOH with the second example, the time when setprecision(3)
is inserted to the stream is very well defined - i.e. after endl
is inserted and before test
(2nd time). Therefor the first version will not produce reliable results (what you get may be different on different implementations), but the second version will.
See this question for a more detailed explanation. (The question there doesn't use operators, but the principle is the same - calling a member function on the return value of another function.)
来源:https://stackoverflow.com/questions/35285481/why-does-cout-precision-affect-the-whole-stream