booling Around
In the pre-
bool era, C++ libraries often used
void* as the target type of a Boolean conversion operator. The
<fstream> library is an example of this. Will
void* save the day? Indeed, a
void* conversion operator prevents nonsensical expressions such as
p1+p2 from compiling:
template <class T>
class Ptr
{
public:
operator void*() const
{
return ((void*) rawptr);
}
};
cout<<"p1 + p2 = "<< p1+p2 <<endl; //compilation error
Ptr <File> pf;
Ptr <Query> pq; // Query and File are unrelated types
if(pf==pq) // so so, compares raw addresses
And yet, a
void* conversion operator introduces new surprises:
cout << pf <<endl;//prints raw address, do you want that?
delete pf; //undefined behavior
The Pointer to Member Hack
Recently, C++ pundits have come up with a better idea. Instead of using bool or
void*, classes such as
std::tr1::shared_ptr use
pointers to members as the target type of a Boolean conversion operator.
Author's Note: The terms "conversion to bool" and "conversion to Boolean" aren't interchangeable. In the former, bool is the target type. The latter however uses an unspecified type that's convertible to bool. |
Let's look at a concrete implementation of this technique.
First, add a nested struct that has one data member to class Ptr (code changes are highlighted):
template <class T>
class Ptr
{
private:
struct PtrConversion
{
int valid;
};
};
Next, declare a
typedef that serves as a synonym for "pointer to an
int member of
PtrConversion":
template <class T>
class Ptr
{
private:
struct PtrConversion
{
int valid;
};
public:
typedef int PtrConversion::*pmi;
};
Finally, define a public conversion operator whose target type is
pmi:
public:
operator pmi() const //conversion to Boolean
{
return rawptr? &PtrConversion::valid : 0;
}