Solution
The answer is: No, bool's effect could
not have been duplicated without adding a builtin type. The
bool builtin type, and the reserved keywords true
and false, were added to C++ precisely because they
couldn't be duplicated completely using the existing language.
This Item is intended to illustrate the
considerations you have to think about when you design your own
classes, enums, and other tools.
The second part of the Item question was: If no,
show why possible implementations do not behave the same as the
builtin bool.
There are four major implementations.
Option 1: typedef (score: 8.5
/ 10)
This option means to "typedef
<something> bool;", typically:
// Option 1: typedef
//
typedef int bool;
const bool true = 1;
const bool false = 0;
This solution isn't bad, but it doesn't allow
overloading on bool. For example:
// file f.h
void f( int ); // ok
void f( bool ); // ok, redeclares the same function
// file f.cpp
void f( int ) { /*...*/ } // ok
void f( bool ) { /*...*/ } // error, redefinition
Another problem is that Option 1 can allow code
like this to behave unexpectedly:
void f( bool b )
{
assert( b != true && b != false );
}
So Option 1 isn't good enough.
Option 2: #define (score: 0 /
10)
This option means to "#define bool
<something>", typically:
// Option 2: #define
//
#define bool int
#define true 1
#define false 0
This is, of course, purely evil. It not only has
all the same problems as Option 1, but it also wreaks the usual
havoc of #defines. For example, pity the poor customer who
tries to use this library and already has a variable named
false; now this definitely behaves differently from a
builtin type.
Trying to use the preprocessor to simulate a
type is just a bad idea.
Option 3: enum (score: 9 /
10)
This option means to make an "enum
bool", typically:
// Option 3: enum
//
enum bool { false, true };
This is somewhat better than Option 1. It allows
overloading (the main problem with the first option), but it
doesn't allow automatic conversions from a conditional expression
(which would have been possible with the first option), to wit:
bool b;
b = ( i == j );
This doesn't work, because ints cannot
be implicitly converted to enums.
Option 4: Class (score: 9 /
10)
Hey, this is an object-oriented language, right?
So why not write a class, typically:
class bool
{
public:
bool();
bool( int ); // to enable conversions from
bool& operator=( int ); // conditional expressions
//operator int(); // questionable!
//operator void*(); // questionable!
private:
unsigned char b_;
};
const bool true ( 1 );
const bool false( 0 );
This works except for the conversion operators
marked "questionable." They're questionable because:
-
With an automatic conversion, bools
will interfere with overload resolution, just as do all classes
having non-explicit (conversion) constructors and/or
implicit conversion operators, especially when the conversion is
from or to a common type. See Items 20 and 39 for more about
implicit conversions.
-
Without a conversion to something like
int or void*, bool objects can't be
tested "naturally" in conditions. For example:
bool b;
/*...*/
if( b ) // error without an automatic conversion to
{ // something like int or void*
/*...*/
}
It's a classic Catch-22 situation: We must
choose one alternative or the other—either provide an automatic
conversion or not—but neither option lets us duplicate the effect
of having a builtin bool type. In summary:
-
A typedef ... bool wouldn't allow
overloading on bool.
-
A #define bool wouldn't allow
overloading either and would wreak the usual havoc of
#defines.
-
An enum bool would allow overloading
but couldn't be automatically converted from a conditional
expression (as in "b = (i == j);").
-
A class bool would allow overloading
but wouldn't let a bool object be tested in conditions (as
in "if( b )") unless it provided an automatic conversion
to something like int or void*, which would wreak
the usual havoc of automatic conversions.
And, finally, there's one more thing (related to
overloading) that we couldn't have done otherwise, either, except
perhaps with the last option: Specify that conditional expressions
have type bool.
So, yes, we really did need a builtin
bool.
|