Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
294 views
in Technique[技术] by (71.8m points)

c++ - Why does std::basic_ios overload the unary logical negation operator?

The C++ IO streams' base class std::basic_ios defines operator void*() to return !fail() and operator!() to return fail(). That makes me wonder why we need the operator!() at all. Certainly, !is would also work by implicitly calling operator void*() and negating its result.

Am I missing something here or is it purely for historical reasons that std::basic_ios::operator!() is defined?

A question on comp.lang.c++.moderated didn't bring any answers either.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

With old (read: not long after cfront) C++ compilers, the compiler was not guaranteed to implicitly call typecast operators on objects when needed. If iostream didn't have an operator ! declared, then you couldn't expect !cout to work in all cases. C++89 (or whatever the pre-C++98 standard was called) simply left the area undefined.

This is also why operator void*() was overloaded, and not operator int or operator bool. (bool didn't even exist as its own type in the standard at that point.) I remember my professor telling me that if(), under the hood, expected a void* in C++, because that type could act as a "superset" type relative to those expression result types that would be passed to an if statement, but I have not found this spelled out anywhere.

This was around the time of gcc 2, when most folks didn't support templates or exceptions, or if they did, didn't fully support them, so metaprogramming C++ with templates was still a theoretical exercise and you made sure to check that operator new didn't return a null pointer.

This drove me nuts for several years.

An interesting excerpt from Stroustrup's The C++ Programming Language, 3rd ed. (1997), page 276:

The istream and ostream types rely on a conversion function to enable statements such as

while (cin >> x) cout << x;

The input operation cin>>x returns an istream&. That value is implicitly converted to a value indicating the state of cin. The value can then be tested by while. However, it is typically not a good idea to define an implicit conversion from one type to another in such a way that information is lost in the conversion.

There's a lot in C++ that seems to be a victory of cute or clever over consistent. I wouldn't mind one bit if C++ was smart enough to handle the above loop as:

while (!(cin >> x).fail()) cout << x;

because this, while more verbose and more punctuation, is clearer to a beginning programmer.

... Actually, come to think of it, I don't like either of those constructs. Spell it out:

for(;;)
{   cin >> x;
    if(!cin)
        break;
    cout << x;
}

Why do I like this better? Because this version makes it far clearer how to expandthe code to, say, handle two reads at a time instead of one. For example, "The existing code copies a sequence of float values. We want you to change it so it pairs up the float values and writes them out, two per line, because we're now using complex numbers."

But I digress.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...