The C++ IO streams' base class std::basic_ios defines operator void*()
to return a safe bool indicating !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 (mistaken) historical
reasons that std::basic_ios::operator!() is defined?
Thanks,
sbi
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
For a brief time in the 90s (4 months to be exact) the then working
paper for C++ supplied an operator bool for IO streams. Unfortunately
the horrible compromise made to get bool into the language as a
fundamental type returned by such things as comparison operators meant
that with that specification such things as:
std::cin << x;
became valid.
The fix was to provide operator void* instead (a null pointer would then
be equivalent to false, but applying such things as shift operators
would result in compile time errors)
operator! has been in the specification for as long as I can remember
and leaving it alone seems harmless (if it isn't broke do not fix it,
that way it will certainly stay unbroken.
No, I am not, although it seems my posting confused you. I know what
operator void*() does and I know why it isn't operator bool(). (Note that I
wrote "safe bool". <http://www.artima.com/cppsource/safebool.html>) I must
have learned this about 15 years ago.
> operator! has been in the specification for as long as I can remember
> and leaving it alone seems harmless (if it isn't broke do not fix it,
> that way it will certainly stay unbroken.
And what I want to know is: Why do we have operator!() in the first place?
Is there a _technical_ reason I'm missing or is it there just because Jerry
Schwarz or whoever added it was playing around with the then brand new toy
of operator overloading? I am just asking because I can't see a technical
reason. I am perfectly fine either way. I just want to know.
sbi
I suppose the fact that nobody knows how to answer this can be taken as an
indication that there is indeed no technical reason?
For operator void* there are no other reasons but for to allow more
convenient syntax for detection if there were no failures. Instead of
using "if ( !some_basic_ios.fail() )" or "if ( !!some_basic_ios )" you
may use "if ( some_basic_ios )".
For operator! on the other hand the reason is probably efficiency. Why
to have a pointer converted to bool and then inbuilt operator!()
applied? I have seen bit-wise logic operators used as reasonable
performance optimization to get rid of slowness of something-bool
conversions.
That seemed like a good and valid reason...until I remembered we're talking
streams here. It's input/output. Does the performance of a pointer-to-bool
conversion really matter to test success of reading from or writing to an
external device, including copying of characters (with O(n)!) and probably
even converting other objects to/from string?
That seems like a very dubious reason.
sbi
Templates usually target maximum possible performance, since it is
hard to know when it matters. basic_ios is about stream. stream is
sequence of data coming or going to somewhere.
When stream is for reading/writing very complex to parse data then it
probably gives no effect. When streaming to/from slow external device
then it probably is pointless as well. However when for example two
applications are piped together and use direct streams to interchange
lot of simple to parse data with each other then it may be is saving
cycles?
fail() is anyway there so operator! is not some huge masterpiece ...
it is one-liner synonym declaration.
You got to be kidding. We're talking a pointer-to-bool conversion here
(which is most likely elided and the pointer tested for NULL-ness directly),
compared to the performance of copying a string of characters to/from
somewhere. And that's for the best-case scenarios with no conversions
to/from string and the stream working on memory.
Even in this optimal scenario, the performance of checking a pointer for
NULL-ness compared to checking a boolean for being false certainly doesn't
seem like a valid reason to overload that operator.
> fail() is anyway there so operator! is not some huge masterpiece ...
> it is one-liner synonym declaration.
Yep. An I think that's why it was done. ("...or is it there just because
Jerry Schwarz or whoever added it was playing around with the then brand new
toy of operator overloading?")
Which is all fine, greater sins have been committed in the history of C++
('std::vector<bool>' for starters). But I started out with this question
because I wanted to know whether there is a _technical_ reason.
It seems there is none.
sbi
> The C++ IO streams' base class std::basic_ios defines operator void*()
> to return a safe bool indicating !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 (mistaken) historical
> reasons that std::basic_ios::operator!() is defined?
Probably for reasons of orthogonality. Any time you overload
operator bool() (and the operator void*() is a disguised
overload of operator bool()), you also overload operator!().
It's just good coding practice.
--
James Kanze
James, over the years I have learned to respect your knowledge, but "it's
just good coding practice" isn't enough for me to be convinced by you. If
this was true, there ought to be a reason that's possible to explain. Could
you please cite that reason to back up this statements?
Also, there's contrary evidence. For starters, if this was true, the
standard library's smart pointers should follow that practice. Yet, they don't.
> James Kanze
sbi
> > Probably for reasons of orthogonality. Any time you
> > overload operator bool() (and the operator void*() is
> > a disguised overload of operator bool()), you also overload
> > operator!(). It's just good coding practice.
> James, over the years I have learned to respect your
> knowledge, but "it's just good coding practice" isn't enough
> for me to be convinced by you.
Substitute "usual", or "expected", then, instead of "good".
Psychologically, it's done more or less for the same reason one
overloads != if one overloads ==.
> If this was true, there ought to be a reason that's possible
> to explain.
Today, yes. Everyone does it, and your code sticks out and
looks funny if it doesn't.
> Could you please cite that reason to back up this statements?
> Also, there's contrary evidence. For starters, if this was
> true, the standard library's smart pointers should follow that
> practice. Yet, they don't.
A smart pointer shouldn't convert to a pseudo-bool to begin
with. Just because you're emulating pointers, there's no reason
to emulate their misfeatures. (My smart pointers do support
comparaison with NULL. Both == and !=. For auto_ptr, the only
solution I've seen is ptr.get() == NULL.)
--
James Kanze
If this was indeed so expected, my question would have caused a roar of
people jelling "because!" at me. Yet, I had to repeatedly ask to get even
three opinions on the matter, and not one of them came up with a convincing
reason.
> Psychologically, it's done more or less for the same reason one
> overloads != if one overloads ==.
But there's a difference: a==b cannot be implicitly used by the compiler
when a!=b is required. A !mystream, however, works with the implicit
conversion to a boolean-like type.
>> If this was true, there ought to be a reason that's possible
>> to explain.
>
> Today, yes. Everyone does it, and your code sticks out and
> looks funny if it doesn't.
Except for streams, I cannot remember a single time I have seen operator!
overloaded. I have, OTOH, seen many operator bool-lookalikes. If overloading
operator! was "usual" and "expected" for such types, you'd think I should
have come across it in more than 15 years of C++ coding.
I conclude that you're wrong there. _Nobody_ does it. And why should they?
You still haven't given a rationale. Negating objects works with just an
implicit boolean conversion in place, operator! isn't needed for that.
>> Could you please cite that reason to back up this statements?
>> Also, there's contrary evidence. For starters, if this was
>> true, the standard library's smart pointers should follow that
>> practice. Yet, they don't.
>
> A smart pointer shouldn't convert to a pseudo-bool to begin
> with. [tangent snipped]
Whether this is right or wrong is unimportant here. What's important,
though, is the fact that the designers of the standard library's smart
pointer classes, like me, seem to have never heard about the "usual" and
"expected" overloading of operator!.
Perhaps they, like me, didn't see a reason to do so?
sbi
--
I have been told, that this additional declaration was added to
emphasize
the symmetry between the "true" case and it's negation, just as a
guide
for the reader, nothing more. To be fair, the idiom
operator void*
was rather new at this time and given this the deduction which syntax
support is provided by this feature is not immediately obvious. Other
than that there was no further technical reason to do so.
Nevertheless
you might still find some buggy compilers that don't get the
conversion
right without the additional operator!. As far as I remember
correctly, I
needed to provide operator! additionally for old Borland compilers.
HTH & Greetings from Bremen,
Daniel Krügler
Thanks for your insight. (BTW, can you clarify your "I have been told..."?)
So it is pretty much as I thought: no technical reason.
> Nevertheless
> you might still find some buggy compilers that don't get the conversion
> right without the additional operator!. As far as I remember correctly, I
> needed to provide operator! additionally for old Borland compilers.
Well, if that would indeed still be the case, then I suppose those compilers
would also fail spectacular on the standard library's smart pointers, all of
which only overload operator void*.
> HTH & Greetings from Bremen,
>
> Daniel Krügler
sbi