Allowing a class to be converted to bool?

J

Joseph Turian

Is it possible to allow a class to be converted to bool?

For example, if I have:
class foo {
private:
unsigned i;
};

and I want to evaluate:
if (foo)
by looking at foo.i, how can I do that?

Thanks

Joseph
 
G

Gianni Mariani

Joseph said:
Is it possible to allow a class to be converted to bool?

For example, if I have:
class foo {
private:
unsigned i;
};

and I want to evaluate:
if (foo)
by looking at foo.i, how can I do that?

Use a conversion operator ...

class foo
{
public:
operator bool()
{
return i != 0;
}
.....
 
J

Jonathan Mcdougall

Joseph said:
Is it possible to allow a class to be converted to bool?

For example, if I have:
class foo {
private:
unsigned i;
};

and I want to evaluate:
if (foo)
by looking at foo.i, how can I do that?

class foo
{
public:
operator bool() const
{
return i != 0;
}

private:
unsigned i;
};

But know that this makes it possible for your class to be converted:

foo f;

if (f) ; // cool
int a = f; // .. also works


Jonathan
 
J

Joseph Turian

Jonathan said:
But know that this makes it possible for your class to be converted:

foo f;
if (f) ; // cool
int a = f; // .. also works

Okay wait.

The whole reason I created a class 'foo' which wraps the POD type
'unsigned' is because I want to ensure type-safety by creating several
sub-types of foo.

i.e. I want to have three classes A, B, and C which are essentially of
type 'unsigned'.
However, I want A, B, and C to be considered distinct types and to
have, say, comparisons between A and B types to cause a compiler error.
So, to do so, I want to have A, B, and C inherit from foo.

Question 1: Does having A, B, and C inherit from foo achieve the
desired effect of disallowing comparisons and casts between types A, B,
and C?
Question 2: Does adding the operator bool conversion function open me
to any type-conversion risks?


Thanks!

Joseph
 
G

Greg

Joseph said:
Okay wait.

The whole reason I created a class 'foo' which wraps the POD type
'unsigned' is because I want to ensure type-safety by creating several
sub-types of foo.

i.e. I want to have three classes A, B, and C which are essentially of
type 'unsigned'.
However, I want A, B, and C to be considered distinct types and to
have, say, comparisons between A and B types to cause a compiler error.
So, to do so, I want to have A, B, and C inherit from foo.

Question 1: Does having A, B, and C inherit from foo achieve the
desired effect of disallowing comparisons and casts between types A, B,
and C?
Question 2: Does adding the operator bool conversion function open me
to any type-conversion risks?

Yes. Implicitly converting to a bool would open the door to type
conversions that you probably would not want.

In this case, you can lift a page from boost shared_ptr and return a
dummy member function pointer. Member function pointers are
sufficiently restricted that a program cannot do much with one beyond
testing it for NULL.

class foo
{
private:
unsigned i;

typedef unsigned foo::*unspecified_bool_type;

public:
foo() : i(0) {}

operator unspecified_bool_type() const
{
return i ? &foo::i : NULL;
}
};

Now:

foo f;

if (f) {} // OK
int a = f; // Error

Greg
 
A

anujanujdhamija

If you have 3 classes A, B and C which contain unsigned int member.
These cant be compared with each other unless you provide a conversion
operator to a common type (say unsigned int or bool) in each of these
classes or you overload assignment operator in these classes to allow
such comparison.
If you provide a conversion operator say "operator unsigned int()" in
all 3 classes then when you do if(A==B), this conversion function is
called which converts the operands to unsigned int and then compare
these. When you derive A, B and C from another class foo which provides
another conversion operator "operator bool()", then (A==B) will become
ambiguous as there are two possible conversions before comparison. So
this will disallow the comparisons the way you like.
Regarding type-conversion risk, as mentioned by Jonathan, conversion
operator is invoked whenver you use the class object in boolean context
and wont be restricted only to comparisons.
 
J

Jonathan Mcdougall

Joseph said:
Okay wait.

The whole reason I created a class 'foo' which wraps the POD type
'unsigned' is because I want to ensure type-safety by creating several
sub-types of foo.

Good thing.
i.e. I want to have three classes A, B, and C which are essentially of
type 'unsigned'.
However, I want A, B, and C to be considered distinct types and to
have, say, comparisons between A and B types to cause a compiler error.
So, to do so, I want to have A, B, and C inherit from foo.

"So"? If you want A, B and C yo be considered distinct types, don't
derive them from a base class!
Question 1: Does having A, B, and C inherit from foo achieve the
desired effect of disallowing comparisons and casts between types A, B,
and C?

No, it has no influence. A, B and C cannot be compared or converted
between themselves if you did not write the correct operators. They can
be converted to foo's though.
Question 2: Does adding the operator bool conversion function open me
to any type-conversion risks?

Of course, as do all conversion operators. Consider this:

# include <complex>

class C
{
public:
C(double d);
};

class foo
{
public:
operator bool();
};

int main()
{
foo f;

C c(f); // hmmm
if (f == 'A') ; // oups
std::complex<int> s(f); // what?
}

You could use an operator void* instead:

class foo()
{
public:
operator void*()
{
return i ? &i : 0;
}

private:
int i;
};

If you're careful, that conversion may not be dangerous.

For maximum safety, consider using a named member function. Sometimes,
safety is more important than convenience.


Jonathan
 
J

Jonathan Mcdougall

Regarding type-conversion risk, as mentioned by Jonathan, conversion
operator is invoked whenver you use the class object in boolean context
and wont be restricted only to comparisons.

Actually, it would be more accurate to say that this conversion
operator is considered when an integral type is expected.


Jonathan
 
P

puzzlecracker

Greg said:
Yes. Implicitly converting to a bool would open the door to type
conversions that you probably would not want.

In this case, you can lift a page from boost shared_ptr and return a
dummy member function pointer. Member function pointers are
sufficiently restricted that a program cannot do much with one beyond
testing it for NULL.

class foo
{
private:
unsigned i;

typedef unsigned foo::*unspecified_bool_type;

public:
foo() : i(0) {}

operator unspecified_bool_type() const
{
return i ? &foo::i : NULL;
}
};

Now:

foo f;

if (f) {} // OK
int a = f; // Error

Greg
typedef unsigned foo::*unspecified_bool_type; --
what is ti mean?
 
P

peter koch

Joseph Turian skrev:
Okay wait.

The whole reason I created a class 'foo' which wraps the POD type
'unsigned' is because I want to ensure type-safety by creating several
sub-types of foo.

i.e. I want to have three classes A, B, and C which are essentially of
type 'unsigned'.
However, I want A, B, and C to be considered distinct types and to
have, say, comparisons between A and B types to cause a compiler error.
So, to do so, I want to have A, B, and C inherit from foo.

There is no need to inherit - as Jonathan told you.

An elegant way to allow many such similar classes and have them be
distinct would be to use a template:

template<int id> class personalized_int
{
...
};
The only purpose of the template would be to faciliate the easy
creation of new types - so inside the class template, everything will
look as if the class was nontemplated.

When you're done you can use a typedef to get to a "userfriendly" name:

typedef personalized_int<0> apple_t;
typedef personalized_int<1> orange_t;
orange_t oranges = 10;
apple_t apples = 30;

if (apples < oranges) // causes compile-error


/Peter
 
G

Greg

puzzlecracker said:
typedef unsigned foo::*unspecified_bool_type; --
what is ti mean?

It's a typedef declaration that makes the name "unspecified_bool_type"
an alias for a data member pointer to an unsigned int data member of
foo. The subsequent unspecified_bool_type conversion operator returns
such a data member pointer when i is not 0 or NULL otherwise.

Greg
 

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
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top