C++ stringstream manipulators

Started by
7 comments, last by Kylotan 16 years, 6 months ago
Greetings, I've been playing around with std::stringstreams lately and came across something that I thought was odd. Take the following snippet for example:
std::stringstream s;
s << std::setprecision(2);
s << 7654321.1234567;

std::string number = s.str(); // number becomes "7.7e+006"

std::stringstream s2;
s2 << std::setprecision(2);
s2 << number.c_str(); // s2 contains "7.7e+006"

unsigned int value;
s2 >> value; // value == 7?

std::stringstream s3;
s3 << std::setprecision(2);
s3 << number.c_str(); // s3 contains "7.7e+006"

double value2;
s3 >> value2; // value2 == 7700000.0000000000 as expected
As you can see, the output I got for the unsigned int was unexpected. Can anyone explain this to me?
Advertisement
Quote:Original post by Mantear
Greetings,

I've been playing around with std::stringstreams lately and came across something that I thought was odd. Take the following snippet for example:
*** Source Snippet Removed ***
As you can see, the output I got for the unsigned int was unexpected. Can anyone explain this to me?


The stream reads as many characters as it can while still creating a valid int. It does not try to "read any kind of number" and then cast to an int. It reads the 7, then sees the decimal point, and concludes that the decimal point is not part of the number (because it's an int).
Hmm, are there any standard practices to get around this potential pitfall, then? Any time the stringstream converts an input number to scientific notation, it will not be possible to retrieve it as an unsigned int. At least not directly, I suppose. I could extract the number from the stringstream as a double, then cast to an unsigned int. But how would I know when to do this? I would not want to have to always extract as a double then convert to unsigned int as floating point precision could bite me in some cases.
It won't use scientific notation if you use the std::fixed format flag.
But then it won't round either if that is what you want to achieve.
If you wrote a double (such as the literal 7654321.1234567), it stands to reason that you can read back a double without occurring any truncation or data loss that hasn't already occurred.

Are you really in a situation where you're writing varying types to text willy nilly, with no way to know what said types were? If so, I'd probably read the word first as a std::string, test for the existance of a decimal place and/or exponent (e.g. 'e').

Of course, this is also ignoring that a double on most implementations has more than 32 bits1 of precision anyways, making the "floating point precision" thing a red herring in the first place.
The purpose for all of this is a simple OpenGL GUI I'm playing with. Originally, the widgets that could store a value (like a text box) were storing an enum indicating what type they were and member variables of all valid types (ints, shorts, chars, floats, doubles, etc). This is cumbersome to do, and was hoping to use std::stringstreams to store/retrieve the data.

Currently, in order to store a new value to the text box, I have a templated function that takes any value as an input, passes it through a std::stringstream, and then stores it as a std::string. To retreive the value, I again have a templated function that takes any value type as an input, passes the stored std::string into the std::stringstream, then extracts it to the value. Is this a decent idea, or a really horrible one?
I couldn't really follow what you were saying, but if you're simply asking whether using a stringstream to convert from a string to one of several values is a good idea or not, I think it's a perfectly fine idea.
What I was trying to say was, is it a good idea to use a string to store a generic value for a widget in a GUI system? This way, I can use template methods to set/get the value of the widget and cover many types.

For example, if I have a text box widget, I could have a method like
<typename T> void TextBox::Set(T value)
. The Set() method could be a template function that passes value into a stringstream, when then converts it to a string member variable for storage. Then, whenever I want to retrieve the value of the text box, I could use
template <typename T> void TextBox::Get(T& value)
, first putting the string member variable into a stringstream then extracting it to 'value'.

Does that make sense?
Why do you need to store a value when you don't know what type it is? Surely whichever logic is querying the GUI will know what to expect from a given control.

A TextBox contains Text - hence the name. If you then decide you want that text to be used as a number, that conversion should occur between the GUI and the logic in your app that uses the number. It shouldn't be part of the GUI code itself. By all means, have functions like these that convert to a string (for passing into the TextBox) and converting from a string (to interpret the data) but keep them outside the GUI itself.

Otherwise, as you saw in your original problem, you're essentially placing a burden on the GUI of having to be able to accept any arbitrary type and convert it to another arbitrary type in the 'correct' way. If you just make the GUI a view onto the data, rather than a holding place for the data, you avoid this problem.

This topic is closed to new replies.

Advertisement