Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why does std::basic_ios overload the unary negation operator?

17 views
Skip to first unread message

sbi

unread,
Jul 13, 2010, 9:01:53 AM7/13/10
to
Hallo,

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! ]

Francis Glassborow

unread,
Jul 13, 2010, 6:39:44 PM7/13/10
to
sbi wrote:
> Hallo,
>
> 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?
>
I suspect that you are being confused by the need to sidestep issues
with bool.

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.

sbi

unread,
Jul 13, 2010, 10:49:10 PM7/13/10
to
Francis Glassborow wrote:
> sbi wrote:
>> Hallo,
>>
>> 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?
>>
> I suspect that you are being confused by the need to sidestep issues
> with bool.
> [...]

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

sbi

unread,
Jul 22, 2010, 8:00:38 PM7/22/10
to
sbi wrote:
> [...]

>>> 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?
>
> [...] 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.

I suppose the fact that nobody knows how to answer this can be taken as an
indication that there is indeed no technical reason?

Öö Tiib

unread,
Jul 24, 2010, 10:00:56 AM7/24/10
to
On 23 juuli, 03:00, sbi <non...@invalid.invalid> wrote:
> sbi wrote:
> > [...]
> >>> 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?
>
> > [...] 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.
>
> 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.

sbi

unread,
Jul 28, 2010, 4:48:29 PM7/28/10
to
嘱 Tiib wrote:
> [...]

> 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

Öö Tiib

unread,
Jul 28, 2010, 11:35:46 PM7/28/10
to
On 28 juuli, 23:48, sbi <non...@invalid.invalid> wrote:

> Öö Tiib wrote:
> > [...]
> > 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.

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.

sbi

unread,
Jul 29, 2010, 8:23:56 PM7/29/10
to
嘱 Tiib wrote:
> On 28 juuli, 23:48, sbi <non...@invalid.invalid> wrote:
>> 嘱 Tiib wrote:
>>> [...]
>>> 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.
>
> 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?

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

James Kanze

unread,
Jul 30, 2010, 2:53:47 PM7/30/10
to
On Jul 13, 2:01 pm, sbi <non...@invalid.invalid> wrote:

> 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

sbi

unread,
Jul 31, 2010, 10:33:45 AM7/31/10
to
James Kanze wrote:
> On Jul 13, 2:01 pm, sbi <non...@invalid.invalid> wrote:
> [...]

>> 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, 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

James Kanze

unread,
Aug 4, 2010, 10:10:26 PM8/4/10
to
On Jul 31, 3:33 pm, sbi <non...@invalid.invalid> wrote:
> James Kanze wrote:
> > On Jul 13, 2:01 pm, sbi <non...@invalid.invalid> wrote:
> > [...]
> >> 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, 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

sbi

unread,
Aug 5, 2010, 11:31:36 PM8/5/10
to
James Kanze wrote:
> On Jul 31, 3:33 pm, sbi <non...@invalid.invalid> wrote:
>> James Kanze wrote:
>>> On Jul 13, 2:01 pm, sbi <non...@invalid.invalid> wrote:
>>> [...]
>>>> 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, 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".

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

--

Daniel Krügler

unread,
Aug 12, 2010, 9:02:53 AM8/12/10
to
On 13 Jul., 15:01, sbi <non...@invalid.invalid> wrote:
> Hallo,
>
> 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?

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

sbi

unread,
Aug 22, 2010, 9:04:56 PM8/22/10
to
Daniel Krügler wrote:
> On 13 Jul., 15:01, sbi <non...@invalid.invalid> wrote:
>> Hallo,
>>
>> 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?
>
> 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.

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

0 new messages