Question

I'm learning the Cinder framework. There is a class Texture in this framework, and it can be used like this:

Texture myImage;
myImage.loadImage(/*...*/);
if(myImage)
{
    // draw the image.
}

I got confused about this, because myImage is an object. Using it as a condition doesn't make sense to me. I expected something like myImage.exist();. So I stepped through the code, and it turns out that Texture class has a conversion operator defined:

public:
    //@{
    //! Emulates shared_ptr-like behavior
    typedef std::shared_ptr<Obj> Texture::*unspecified_bool_type;
    // What is this???
    operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &Texture::mObj; }
    void reset() { mObj.reset(); }
    //@}  

Obj is defined as:

protected:      
    struct Obj {
        Obj() : mWidth( -1 ), mHeight( -1 ), mCleanWidth( -1 ), mCleanHeight( -1 ), mInternalFormat( -1 ), mTextureID( 0 ), mFlipped( false ), mDeallocatorFunc( 0 ) {}
        Obj( int aWidth, int aHeight ) : mInternalFormat( -1 ), mWidth( aWidth ), mHeight( aHeight ), mCleanWidth( aWidth ), mCleanHeight( aHeight ), mFlipped( false ), mTextureID( 0 ), mDeallocatorFunc( 0 )  {}
        ~Obj();

        mutable GLint   mWidth, mHeight, mCleanWidth, mCleanHeight;
        float           mMaxU, mMaxV;
        mutable GLint   mInternalFormat;
        GLenum          mTarget;
        GLuint          mTextureID;
        bool            mDoNotDispose;
        bool            mFlipped;   
        void            (*mDeallocatorFunc)(void *refcon);
        void            *mDeallocatorRefcon;            
    };
    std::shared_ptr<Obj>        mObj;

I know that operator int() const can implictly change the Object to int, but how is unspecified_bool_type working? The debugger stops at operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &Texture::mObj; } when if(myImage) is executing.

And I may be a little confused about the grammar here, what does

typedef std::shared_ptr<Obj> Texture::*unspecified_bool_type;

mean?

And does

void (*mDeallocatorFunc)(void *refcon); 

in Obj mean that mDeallocatorFunc is a member of Class Obj, a function pointer to a function with prototype: void xxx(void *)?

Was it helpful?

Solution

This is the safe bool idiom. It doesn't use simply operator bool() because implicit conversions can cause all kinds of trouble with that operator. So instead it uses a type that is implicitly convertible to bool (like a pointer to member) and that is the least dangerous possible.

Luckily this sort of hack is not required in C++11 because we can write explicit operator bool instead and not fall prey to implicit conversions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top