Opposite of ! operator.

J

jason.cipriani

If I have:

class Something {
public:
bool operator ! () const;
};

Then I can do:

Something s(...);
if (!s) ...;

My question is, what operator do I need to overload if I want to be
able to define the behavior of this instead:

Something s(...);
if (s) ...; // <-- notice no !

Sorry if the post title was stupid, I couldn't think of a better one.

Thanks,
Jason
 
W

Wang Yongxin

If I have:

class Something {
public:
bool operator ! () const;
};

Then I can do:

Something s(...);
if (!s) ...;

My question is, what operator do I need to overload if I want to be
able to define the behavior of this instead:

Something s(...);
if (s) ...; // <-- notice no !

Sorry if the post title was stupid, I couldn't think of a better one.

Thanks,
Jason

Maybe you want to overload operator bool().
 
A

Alan Johnson

If I have:

class Something {
public:
bool operator ! () const;
};

Then I can do:

Something s(...);
if (!s) ...;

My question is, what operator do I need to overload if I want to be
able to define the behavior of this instead:

Something s(...);
if (s) ...; // <-- notice no !

Sorry if the post title was stupid, I couldn't think of a better one.

Thanks,
Jason

As others have mentioned the straightforward approach is to implement
operator bool or operator void *. Each of these has some type
conversion drawbacks that aren't immediately obvious. Safe solutions
exist but it gets complicated quickly. See:
http://www.artima.com/cppsource/safebool.html
 
E

Erik Wikström

The common approach is to use

operator const void* () const;

Now you can write:

if (s) ...
if (!s) ...

This should return NULL for 'false' and a non-NULL valid pointer (like
'this') for 'true'. The problem with returning a bool is that it converts
to numeric types too easily and can create hidden errors. Yes, this seems
like a hack, but it's a widely used one.

I'm wondering if the new explicit conversion functions will solve this.
The standard says:

A conversion function may be explicit, in which case it is only
considered as a user-defined conversion for direct-initialization.

Since there is no initialisation going on in "if (s)", I suppose that we
will still have to use the "operator void*" hack.
 
J

James Kanze

I scimmed the page, it seems the only objection to operator
void* raised there is that one can do:
Something s;
delete s;

Not only. For historical reasons, void*'s show up a lot more
than one would like. Although not as dangerous as bool
(although in many cases, even bool isn't that dangerous---it's
major danger in the case of iostream is due to the fact that
iostream overloads << and >>), if you really want safety, it's
not too difficult to return a pointer to a member of a private
class; there's practically nothing a client can do with it
except convert it to bool. This route may be worth going if
you're developing a library which will be used everywhere, and
must be ultra-robust. Otherwise, I'd just go with the operator
bool, unless the class overrides operators which would be valid
on an integral type.
 
G

Gennaro Prota

Pete said:
I'm wondering if the new explicit conversion functions will solve this.
The standard says:

A conversion function may be explicit, in which case it is only
considered as a user-defined conversion for direct-initialization.

Since there is no initialisation going on in "if (s)", I suppose that we
will still have to use the "operator void*" hack.

That would be silly. Take a look at [conv]/4, which defines the term
"contextually converted". Expressions used as conditions are
contextually converted to bool, as if by direct initialization.

Phew :) This wasn't in the proposed 'Changes to the Standard'
of n1592. I emailed the author about it but never got a reply.
 
G

Gennaro Prota

Alan said:
As others have mentioned the straightforward approach is to implement
operator bool or operator void *. Each of these has some type
conversion drawbacks that aren't immediately obvious. Safe solutions
exist but it gets complicated quickly. See:
http://www.artima.com/cppsource/safebool.html

And there's more, for instance to protect against unintended ADL
when you put everything in a reusable base class.

A simpler approach (more an experiment than anything else)
is:

<http://breeze.svn.sourceforge.net/viewvc/breeze/trunk/breeze/idiom/bool_testable.hpp?view=log>
 
D

Daniel T.

If I have:

class Something {
public:
  bool operator ! () const;

};

Then I can do:

Something s(...);
if (!s) ...;

My question is, what operator do I need to overload if I want to be
able to define the behavior of this instead:

Something s(...);
if (s) ...;  // <-- notice no !

Sorry if the post title was stupid, I couldn't think of a better one.

The best solution is to have a named member-function that explains
what the result stands for.

class Something {
public:
bool isOpen() const;
bool isValid() const;
bool isFoo() const;
};

Something s;
if (s.isOpen()) ...;
 
J

Jorgen Grahn

The best solution is to have a named member-function that explains
what the result stands for.

class Something {
public:
bool isOpen() const;
bool isValid() const;
bool isFoo() const;
};

Surely, if you want the operator approach, it's because it's obvious
from the class that there is only one such "boolean-ness". If
Something can be both open/closed, empty/non-empty and valid/invalid,
you probably wouldn't consider allowing "if(something)" anyway.

But I agree that a member is often good enough, or better.
Consider the standard containers and their bool empty() const;
it's no big problem that you cannot write "if(!the_vector) ...".

/Jorgen
 
J

jason.cipriani

As others have mentioned the straightforward approach is to implement
operator bool or operator void *.  Each of these has some type
conversion drawbacks that aren't immediately obvious.  Safe solutions
exist but it gets complicated quickly.  See:http://www.artima.com/cppsource/safebool.html

Thanks guys, that was some interesting info. I've gone with operator
bool.

I have another question. What is the purpose of being able to overload
the unary ! operator? It seems like it would have been less ambiguous
if the rule was convert to bool implicitly then use ! on the resulting
bool, rather than making ! available as an overloadable operator. The
reason I ask is it seems like it's clearer in all cases to just
implement operator bool and not implement operator !.

For example, here is something weird:

class Ambiguous {
public:
operator bool () const { return true; }
bool operator ! () const { return true; }
};

And then I can do:

Ambiguous a;
assert(a && !a); // doesn't read well, does it?


Another weird thing is that it seems that it will use the bool
conversion operator by default if you don't have a ! operator defined:

class A {
public:
operator bool () const { cout << "hi"; return true; }
};

Evaluating "!A();" would print "hi".

So I guess my question is: When would you ever want to override ! but
not bool?

Thanks,
Jason
 
E

Erik Wikström

Thanks guys, that was some interesting info. I've gone with operator
bool.

I have another question. What is the purpose of being able to overload
the unary ! operator? It seems like it would have been less ambiguous
if the rule was convert to bool implicitly then use ! on the resulting
bool, rather than making ! available as an overloadable operator. The
reason I ask is it seems like it's clearer in all cases to just
implement operator bool and not implement operator !.

Your asking the wrong question. The real question is why you shouldn't
be allowed to overload the ! operator? Just because you can't find any
use for it does not mean that someone else can't, and remember, it does
not have to return a bool.
 
J

James Kanze

Your asking the wrong question. The real question is why you
shouldn't be allowed to overload the ! operator? Just because
you can't find any use for it does not mean that someone else
can't, and remember, it does not have to return a bool.

I think his question was why HE should overload the ! operator,
not why the language allows it. IMHO, it's a good question.
I've never actually thought about it; I've always overloaded !
as well, because everyone else always did. (Which is, in a way,
a valid reason.)
 
J

James Kanze

Surely, if you want the operator approach, it's because it's
obvious from the class that there is only one such
"boolean-ness".

Perhaps, but the question still remains: why not be explicit?
If Something can be both open/closed, empty/non-empty and
valid/invalid, you probably wouldn't consider allowing
"if(something)" anyway.

istream and ostream did. In that case, the "meaning" is that
all of the preceding operations succeeded, and it's become a
standard idiom (especially because istream and ostream don't
have any reasonably named functions for this).
But I agree that a member is often good enough, or better.
Consider the standard containers and their bool empty() const;
it's no big problem that you cannot write "if(!the_vector)
...".

In modern code, the main reason for such overloading is for
compatibility. If you're designing a new type of stream (say a
XDRstream), there's something to be said for having it support
the same idioms as the current streams, and if you're
implementing a smart pointer, you obviously want to be able to
compare it to NULL (or any other null pointer constant) and even
support using it as a boolean value: poor programming practice
or not, you can do it with a pointer. (Note that implementing
the comparison with a null pointer constant, while not
supporting arbitrary comparisons with int's, is pretty much the
same problem in reverse---you implement a comparison to some
unnamable pointer type, and the only way client code can get an
instance of this pointer type is through a null pointer
conversion.)
 
J

jason.cipriani

Your asking the wrong question. The real question is why you shouldn't
be allowed to overload the ! operator? Just because you can't find any
use for it does not mean that someone else can't, and remember, it does
not have to return a bool.


If it didn't return a bool, it seems like the ! operator wouldn't be
the most appropriate one to overload. If you implemented a ! operator
that returned some value that meant something besides "didn't fail" or
"wasn't false" or "wasn't 0", then you're ! means something very
different from the meaning of ! in the vast majority of other
contexts, which just ends up being confusing. For that same reason I
never really liked the use of bit shifting operators for istream/
ostream, but in that case the usage was so common it became an idiom.

So I guess my question is based more on my own opinion that if "!x"
doesn't return the same thing as "!(bool)x" then something is amiss.
Also keep in mind the default operator ! does indeed return "!(bool)
x", so to change it's meaning would at least require clear
documentation that you significantly changed something. The same would
go for, say, overloaded binary - and having it mean something
different than the opposite of binary +. Even though you can do it, it
seems unclear.

JC
 
E

Erik Wikström

If it didn't return a bool, it seems like the ! operator wouldn't be
the most appropriate one to overload. If you implemented a ! operator
that returned some value that meant something besides "didn't fail" or
"wasn't false" or "wasn't 0", then you're ! means something very
different from the meaning of ! in the vast majority of other
contexts, which just ends up being confusing. For that same reason I
never really liked the use of bit shifting operators for istream/
ostream, but in that case the usage was so common it became an idiom.

So I guess my question is based more on my own opinion that if "!x"
doesn't return the same thing as "!(bool)x" then something is amiss.
Also keep in mind the default operator ! does indeed return "!(bool)
x", so to change it's meaning would at least require clear
documentation that you significantly changed something. The same would
go for, say, overloaded binary - and having it mean something
different than the opposite of binary +. Even though you can do it, it
seems unclear.

Yes, I agree, but you asked what the purpose of being able to overload
the ! operator was. The reason I pointed out that it does not have to
return a bool was to allude to the fact that the C++ standard tries not
to limit the ways in which we use the language, even if that sometimes
means that some constructs might not make much sense. However one could
for instance use operator overloading and templates to create a domain
specific language where it might make more sense.
 
M

Martin Eisenberg

So I guess my question is based more on my own opinion that if
"!x" doesn't return the same thing as "!(bool)x" then something
is amiss.

To preserve the intuition where it applies in the first place, the
weaker condition bool(!x) == !bool(x) is enough.


Martin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,167
Messages
2,570,910
Members
47,453
Latest member
MadelinePh

Latest Threads

Top