1

Hey guys, I have derived my class from the C++ safe bool idiom class from this page : The Safe Bool Idiom by Bjorn Karlsson

class Element : public safe_bool<>
{
public:
    bool Exists() const;
    // boolean_test() is a safe_bool method
    bool boolean_test() const { return Exists(); }; 
};

When I tried to use it in the if expression like below

Element ele;
...
if(ele)

I got an error C2451: conditional expression of type 'Element' is illegal. If I try to cast it to bool like below, I got this error

Element ele;
...
if((bool)ele)

error C2440: 'type cast' : cannot convert from 'Element' to 'bool'

This is the 1st time I am using safe bool idiom, I am not sure if this is not allowed or a bug in Visual C++ 10. Any comments? Thanks in advance!

ShawnWong
  • 11
  • 1

2 Answers2

1

The safe bool idiom is allowed, although I typically write it like this:

class Element
{
public:
    bool Exists() const;

    /* Begin Safe Bool Idiom */

private:
    // This is a typedef for pointer to an int member of Element.
    typedef int Element::*SafeBoolType;
public:
    inline operator SafeBoolType() const
        { return Exists() ? &Element::someDataMember : 0; }
    inline bool operator!() const
        { return !Exists(); }

    /* End Safe Bool Idiom */

private:
    int someDataMember; // Pick any data member
    // ...
};

This how I've seen it implemented. In fact, Boost implements the idiom in this manner for the smart pointer classes (using an include file).

In silico
  • 51,091
  • 10
  • 150
  • 143
  • I guess it is a bad idea for me to use safe bool idiom because in my class, there is already an operator int() method. Element is a data variant class. I am dropping safe bool idiom idea. Thanks for your sample code!! – ShawnWong Dec 15 '10 at 00:40
  • @ShawnWong: Have you tried to see if it works? The typedef doesn't have to point to an `int` - you can have it point to *any* data member. Also, it's typically not the best idea to have a conversion operator like `operator int()` in the first place. – In silico Dec 15 '10 at 01:01
0

It doesn't seem to compile with any compiler. Apparently safe_bool cannot return the address of a protected method in its base. You should add a public method to safe_bool_base and return the address of that.

Also, it seems that operators == and != are disabled using a non-dependent construct (may cause an error even if not instantiated).

Perhaps this fixes things:

 class safe_bool_base {
  protected:
    typedef void (safe_bool_base::*bool_type)() const;
  private:
    void cannot_compare_boolean_results() const {}
  public:
    void public_func() const {}
  protected:
    safe_bool_base() {}
    safe_bool_base(const safe_bool_base&) {}
    safe_bool_base& operator=(const safe_bool_base&) {return *this;}
    ~safe_bool_base() {}
  };

  template <typename T=void> class safe_bool : public safe_bool_base {
  public:
    operator bool_type() const {
      return (static_cast<const T*>(this))->boolean_test()
        ? &safe_bool_base::public_func : 0;
    }
  protected:
    ~safe_bool() {}
  };

  template<> class safe_bool<void> : public safe_bool_base {
  public:
    operator bool_type() const {
      return boolean_test()==true ? 
        &safe_bool_base::public_func : 0;
    }
  protected:
    virtual bool boolean_test() const=0;
    virtual ~safe_bool() {}
  };

  template <typename T, typename U> 
    bool operator==(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
      lhs.cannot_compare_boolean_results(); //call private method to produce error
      return false;
  }

  template <typename T,typename U> 
  bool operator!=(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
    lhs.cannot_compare_boolean_results(); //call private method to produce error
    return false;   
  }
visitor
  • 8,564
  • 2
  • 26
  • 15
  • I can compile the code in the article, it is just that when I use my class in the conditional expression, it fails to compile. Even your amended code generates "error C2451: conditional expression of type 'Element' is illegal" – ShawnWong Dec 15 '10 at 00:34