- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Actually, calling
operator void*
(though it would be a bit more readable with astatic_cast
instead of an explicit operator call) was a very valid way of checking the stream state up until C++11. That conversion was removed in C++11 and replaced with a conversion of the stream tobool
, which means that the return statement of this function could just sayreturn iss && iss.eof()
. My guess would be that changing the compiler also changed the default C++ standard that the code is compiled with. Maybe that's a WTF right there.Admin
Is not how I'd do it, as there's no reason to capture the return from
iss >> v
because that return will be a reference toiss
itself, so you can askiss
directly:What's worse is that the original version tests the state via
i
, but also directly ontoiss
...Admin
Isn't there a version of atoi in modern libraries which doesn't require creating objects and works in a C++ way? Like int.Parse in C#
Admin
Yes there is; the function is named stoi: https://www.cplusplus.com/reference/string/stoi/
Admin
std::stoi()
apparently if using C++11 or greater.https://stackoverflow.com/questions/7663709/how-can-i-convert-a-stdstring-to-int
Admin
I think I prefer std::from_chars, which is available in C++17. (Probably also available in various TRs for C++11, but I haven't checked.)
The question we should be asking is, what happens if you supply a string which is "almost" an integer? Apparently std::stoi will parse "11x" as "11", which is clearly wrong. So you'd need to use a regexp to sanitise the input , which seems extreme. std::from_chars at least includes an optional parameter for the base, which makes sense to me.
And it's reasonable to complain about the various messy bits of the standard library, but then you're still faced in the OP with a construct that does something "magical" with a strstream, and you probably don't understand the edge cases (I don't), so you're no better off with any version of the hand-crafted string parsing thing.
To Debra: Yes. In fact, the default in 4.x -> 5.x went from gnu89 to gnu11, which is very, very likely to be a breaking change. Also a long overdue one IMHO. And I would prefer my C++ gurus (or even cow-orkers) to understand that going from one major version of the compiler to another major version is very very likely to do this, so it's only a WTF in that nobody in the OP dev environment appeared to expect it.
All in all, an entertaining post about operator overloading, except not really, because a C++ programmer is expected to understand operator << on strings in precisely the same way that they are expected operator + on integers. It gets a bit dicier with operator ++, what with the overload for pre and post, but C++ programmers are expected to understand those too.
Calling out the operator explicitly in a "fluid" fashion -- let alone calling out the cast operator in a fluid fashion -- is, however, evidence of a diseased mind.
Admin
C++ is to foot guns as an A-10 gatling gun is to a pea shooter
Admin
I looked at a stoi as well as other suggestions on StackOverflow and it looks like the closest there is in C++ to a validated string to number parsing is Qt library. It behaves like int.TryParse in .NET, which is as close as possible to the perfect behavior for this kind of operation.
Admin
I've been thinking about this some more, and it's starting to seem like someone who'd have used
sscanf
to do it in C back in the day. It's surprisingly simple to do once you know the incantation, but desperately fragile, while this thing with stringstreams suffers from slowness and opacity, but is far less fragile.Admin
Relatedly, at long last, C++20 finally introduced the Formatting Library (https://en.cppreference.com/w/cpp/utility/format) as part of STL. That one was badly needed (unless you just used Boost).
In response to SPOV's question about "11x" vs "11" - that's what the iss.eof() checks. If the istringstream is done parsing the "11" and is looking at an "x" instead of EOF, it'll fail that check. What can be frustrating is that trailing spaces will trip it as well (especially frustrating because trimming a string is not a simple STL call)
Admin
TRWTF is the C++ library lacking a decent implementation of something so common as string->int for so long. The fixed WTF is much more elegant in retrospect and even the original WTF is not as bad as it seemed.
Admin
You often get things like this in really old code, possibly ported from a different languages, where features simply didn't exist.
Admin
True, yes, that's what the eof checks. But being told that you fail because the parser can't understand the string format of the integer isn't really all that useful, is it?
Admin
Original submitter here, Yeah, part of the WTF is definitely me not knowing much (yet) about that part of C++:
Admin
@kind of related: "What can be frustrating is that trailing spaces will trip it as well"
That's because you need to approach parsing the right way - not divide the input into pieces and parse each piece, but go strictly left to right. So parsing an integer using std::stoi() should use the pos parameter to find out where parsing stopped and then check that what followed the integer is appropriate. That not only makes the plain integer case easy, it also makes much more complex cases easy. For example, if you want to accept things like "10K" for 10000 or "10*57" is you're accepting some form of expression.
Admin
Original submitter still, for a last confession (Sunday is a good time for it too): past me came back with a big stick and hit me hard with it calling me a moron. Why? As probably happens to any half-decent C++ programmer, years ago I needed something like this, and I had written " (iss >> v) && iss.eof()" for the very reasons mentioned in the comments (it does the job and it works before and after C++11). So why not use it this time? Well I was so puzzled by this bizarre explicit call to "operator void*()" that I forgot the big picture. In other words I was "overloaded with details", and I suspect even Remy did not realize how accurate his title was.