65.9K
CodeProject is changing. Read more.
Home

Reusable safe_bool Implementation

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4 votes)

Jan 12, 2010

CPOL
viewsIcon

16684

Reusable safe_bool implementation

safe_bool - what & why[^]?

In my understanding their implementation is broken (if fixable), but in the course I came up with my own that appears slightly more elegant to me:

template <typename T>
class safe_bool 
{
protected:
   typedef void (safe_bool::*bool_type)() const;
   bool_type to_bool_type(bool b) const 
    { return b ? &safe_bool<T>::safe_bool_true : 0; }
 
private:
   void safe_bool_true() const {}
   bool operator ==(safe_bool<T> const & rhs); 
   bool operator !=(safe_bool<T> const & rhs); 
};

Can be used like this:

struct A : public safe_bool<A>
{
   operator bool_type() const { return to_bool_type(true); }
   // replaces:
   // operator bool() const { return true; }
};

From all samples I found that's the cleanest to write and read, while only the two symbols bool_type and to_bool_type "escape" to derived classes.

I am putting this up for review, since I'm clearly at the limits of my understanding of the standard. However, the following test cases pass on VC 2008:

struct A : public safe_bool<A>
{
   operator bool_type() const { return to_bool_type(true); }
};
 
struct B : protected safe_bool<B> // protected is ok, too
{
   operator bool_type() const { return to_bool_type(false); }
};
 
struct C : public B
{
   operator bool_type() const { return to_bool_type(rand() < RAND_MAX / 2); }
}; 

void SafeBootCompileFails()
{
   A a, a2;
   B b;
   C c;
 
   if (a) {}      // Yes!
   if (!a) {}     // Yes!

   a=a;           // Yes! (default assignment op should be allowed)
   a=a2;          // Yes! (default assignment op should be allowed)

   long l = a;    // No!

   if (a==a2) {}  // No!
   if (a!=a2) {}  // No!
   if (a<a2)  {}  // No!

   if (a==b) {}   // No!
   if (a!=b) {}   // No!
   if (a<b)  {}   // No!
   
   if (b==c) {}   // No!
   if (b!=c) {}   // No!
   if (b<c)  {}   // No!

   a=b;           // No!

   b = c;         // Yes, slicing. Not my problem today.
}