Как работает это преобразование в bool?

Я изучаю структуру Cinder. В этом фреймворке есть класс Texture, и его можно использовать так:

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

Я запутался в этом, потому что myImage — это объект. Использование его в качестве условия не имеет для меня смысла. Я ожидал чего-то вроде myImage.exist();. Итак, я прошелся по коду, и оказалось, что в классе Texture определен оператор преобразования:

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(); }
    //@}  

Объект определяется как:

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;

Я знаю, что operator int() const может неявно изменить объект на int, но как работает unspecified_bool_type? Отладчик останавливается на operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &Texture::mObj; }, когда выполняется if(myImage).

И я могу немного запутаться в грамматике здесь, что значит

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

иметь в виду?

И делает

void (*mDeallocatorFunc)(void *refcon); 

в Obj означают, что mDeallocatorFunc является членом класса Obj, указателем функции на функцию с прототипом: void xxx(void *)?


person shengy    schedule 10.01.2012    source источник
comment
Похоже на какое-то заклинание безопасной логической идиомы...   -  person Kerrek SB    schedule 10.01.2012
comment
@KerrekSB Думаю, я понял, он определяет оператор преобразования, который может преобразовать Texture в shared_ptr<Obj>, а остальную часть проверки обеспечивает shared_ptr<Obj>. Но что означает typedef std::shared_ptr<Obj> Texture::*unspecified_bool_type;?? есть ли разница с typedef std::shared_ptr<Obj> unspecified_bool_type; ? Меня смущает такая грамматика, особенно ::* не могли бы вы мне помочь? большое спасибо.   -  person shengy    schedule 10.01.2012
comment
Эта вещь, в частности, является указателем на член (который не является обычным указателем!), но помимо этого я недостаточно читал код. Существует много популярных способов реализации SBI, поэтому, если вы немного поищите, вы можете найти описание, очень похожее на ваш код...   -  person Kerrek SB    schedule 10.01.2012
comment
@KerrekSB, значит, после typedef std::shared_ptr<Obj> Texture::*unspecified_bool_type;, если я напишу unspecified_bool_type var;, то var означает указатель на shared_ptr‹Obj›, и он должен указывать на элемент Texture?   -  person shengy    schedule 10.01.2012
comment
@shengy: В частности, учитывая typedef std::shared_ptr<Obj> Texture::*unspecified_bool_type;, unspecified_bool_type является указателем на член данных Texture типа std::shared_ptr<Obj>. Возврат указателя этого типа никогда не создает новый экземпляр shared_ptr<>.   -  person ildjarn    schedule 11.01.2012


Ответы (1)


Это идиома безопасного логического значения. Он не использует просто operator bool(), потому что неявные преобразования могут вызвать всевозможные проблемы с этим оператором. Поэтому вместо этого он использует тип, который неявно преобразуется в bool (например, указатель на элемент) и является наименее опасным из возможных.

К счастью, в C++11 такой хак не требуется, потому что вместо этого мы можем написать explicit operator bool и не стать жертвой неявных преобразований.

person R. Martinho Fernandes    schedule 10.01.2012
comment