Operator overloading is one of those "dangerous" features. Like multi-parent inheritance, it can potentially create some really expressive, easy to read code, or it can create a disaster of incomprehensible nonsense.
In C++, many core classes use operator overloading, most notably the I/O classes, which reuse (or abuse) the bitshift operators into stream operators. So, for example, one possible way of converting a string into an integer might be to do something like this:
bool str2val(const string &s, int &v) {
std::istringstream iss(s);
istream &i = (iss >> v);
bool b = (!(i.fail() || i.bad())) && iss.eof();
return b;
}
As I'm reconstructing this example from our submitter's notes, any error in this code is mine.
This particular example converts a string
into an istringstream
- wrapping an input stream around a string. Then, using the >>
operator, attempts to read the contents of that stream into an integer variable. This, again, is one of those operator overloads. It also returns an istream
object, which we can then use to check the status of the conversion.
Now, this particular example comes from Gaetan, who didn't implement it because it was the best way to convert strings to integers. Instead, this is a compromise solution, that I included first so that we can understand what the code is supposed to do.
Gaetan's interaction with this code started, as so many legacy projects do, with "it doesn't compile." A fifteen year old code block, which had compiled just fine under GCC 4.8.0 stopped compiling under GCC 5.5.0.
Gaetan pulled up the code, and found this:
bool str2val(const string &s, int &v) {
std::istringstream iss(s);
bool b = iss.operator >>(v).operator void*() != 0 && iss.eof();
return b;
}
This code does the same thing as the above block, but without any hint of readability. Instead of using the overloaded operator as an operator, the original developer instead invokes it like a function, and then invokes a conversion to void*
, which is utter nonsense. In fact, it was that specific conversion which GCC 5+ balked on, but which GCC 4.8.0 did not mind in the least. The comparison against 0
was just a hack-y way to see if the fail
/bad
bits were set.
There's no reason to write the code this way, except perhaps because you have a really deep understanding of C++ syntax and really want to show it off. Gaetan is not a C++ wizard, so when re-implementing this code in a way that compiled, they did their best to re-implement it as close as possible to the original implementation.
Just, y'know, in a way that was readable, that compiled, and didn't depend on some type-punning magic to work.