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

时光怂恿深爱的人放手 提交于 2020-01-24 16:33:45

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!