Boost logo

Boost :

From: Powell, Gary (powellg_at_[hidden])
Date: 2004-02-11 18:18:22


--------------------------------
If Rani is right about the reference binding I'd like to find some way
to library-ize this idiom, so your "ref" converting constructor will
come in handy. BTW, you don't need the other "ref" constructor
anymore.

-- 
Dave Abrahams
----------------------------------------------------------------------
Ok, reusing Andrei's mojo name I've got the following working:
template <class T>
class mojo 
{
protected:
    struct ref
    {
        template<class T2>
        ref(T2 *rhs) : p(rhs) {} // works if there is a conversion.
        template<class T2>
        ref(mojo<T2> *rhs) : p( static_cast<T *>(rhs) ) {} // works if there is a conversion.
        template<class T2>
        ref(mojo<T2> &rhs) : p( static_cast<T *>(rhs.p) ) {} // works if there is a conversion.
        T * p; 
        T *operator->() const
        {
            return p;
        }
        T *operator&() const
        {
           return p;
        }
    };
    mojo() {} // intended to be derived from.
public:    // Move stuff
    operator ref() {
        return ref(this);
    }
};
struct X : public mojo<X>
{
....
    // non-const rvalue
    X(mojo<X>::ref rhs)
      : id(++cnt)
      , owner(rhs->owner)
    {
        std::cout << "MOVE X#" << id << " <== X#" << rhs->id << " owner = " << std::boolalpha << rhs->owner << std::endl;
        rhs->owner = false;
        assert(owner);
    }
....
};
struct Y : public X, public mojo<Y>
{
....
    // non-const rvalue
    Y(mojo<Y>::ref rhs)
      : X ( &rhs )
      , id(++cnt)
      , owner(rhs->owner)
    {
        std::cout << "MOVE Y#" << id << " <== Y#" << rhs->id << " owner = " << std::boolalpha << std::boolalpha << rhs->owner << std::endl;
        rhs->owner = false;
        assert(owner);
    }
...
};
struct V : virtual public X, public mojo<V>
{
....
    // non-const rvalue
    V(mojo<V>::ref rhs)
      : X( &rhs)
      , id(++cnt)
      , owner(rhs->owner)
    {
        std::cout << "MOVE V#" << id << " <== V#" << rhs->id << " owner = " << std::boolalpha << rhs->owner << std::endl;
        rhs->owner = false;
        assert(owner);
    }
...
};
same for class W. (virtual inheritence)
struct U : virtual public V, virtual public W, public mojo<U>
{
....
    // non-const rvalue
    U(mojo<U>::ref rhs)
      : X( &rhs )
      , V( &rhs )
      , W( &rhs )
      , id(++cnt)
      , owner(rhs->owner)
    {
        std::cout << "MOVE U#" << id << " <== U#" << rhs->id << " owner = "  << std::boolalpha << rhs->owner << std::endl;
        rhs->owner = false;
        assert(owner);
    }
...
};
And it all seems to work correctly.
IMO it's not too bad of a "library" module. In any case I like using the operator->() as you can stop referencing the pointer "ref.p". And I chose operator &() but perhaps a "get() member fn of mojo is the right thing to do. As to whether to call it mojo or not...well I didn't have another class name in mind.
If you don't have mulitiple inheritence you don't have to specify mojo<Type>::ref, so that's nice as well.
Anyway I saw Bjarne's call for items on the list, and IMO, this topic deserves it if nothing more than to clarify that its OK.
  -Gary-

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk