Boost logo

Boost :

From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2004-07-29 05:25:39


David Abrahams <dave_at_[hidden]> writes:

> Anthony Williams <anthony_w.geo_at_[hidden]> writes:
>
>> The default implementation of swap is generally along the lines of
>>
>> template<typename T>
>> void swap(T& lhs,T& rhs)
>> {
>> T temp(lhs);
>> lhs=rhs;
>> rhs=temp;
>> }
>>
>> The initialization of temp creates a genuine copy of the data.
>
> How so? Didn't you say that *i is a reference to a tuple of
> references?

With some nifty code that ensures copies are real copies (which you commented
was evil and sneaky). The type is
OwningRefTuple<boost::tuple<type1,type2,type3...> > and derives from
boost::tuple<type1&, type2&,type3&...>

> That makes T a tuple of references, and the
> initialization of a tuple of references just copies a bunch of
> pointers IIUC.

Yes. That's why the nifty code is there.

Time for some code.

MakeTupleTypeWithReferences does just that --- it takes a tuple and produces a
new tuple type where every element is a reference to the corresponding type in
the original tuple.

OwningBase is there to ensure that the owned data is initialized before we try
and bind references to it (if necessary).

OwningRefTuple binds it all together.

    namespace detail
    {
        struct PreserveReferences
        {};

        template<typename OwnedType>
        struct OwningBase
        {
            std::auto_ptr<OwnedType> tupleBuf;

            OwningBase()
            {}
            
            template<typename SomeType>
            OwningBase(SomeType &source):
                tupleBuf(new OwnedType(source))
            {}
            
        };

        template<typename SourceTuple>
        struct MakeTupleTypeWithReferences
        {
            typedef MakeTupleTypeWithReferences<typename SourceTuple::tail_type> TailTupleTypeBuilder;
            typedef typename TailTupleTypeBuilder::Type TailTupleType;
            typedef boost::tuples::cons<typename boost::add_reference<typename SourceTuple::head_type>::type,
                                        TailTupleType> Type;

            template<typename Tuple>
            static Type makeTuple(Tuple& source)
            {
                return Type(source.get_head(),TailTupleTypeBuilder::makeTuple(source.get_tail()));
            }
        };
    
        template<>
        struct MakeTupleTypeWithReferences<boost::tuples::null_type>
        {
            typedef boost::tuples::null_type Type;

            static Type makeTuple(boost::tuples::null_type)
            {
                return Type();
            }
        };
    }

    template<typename TupleType>
    struct OwningRefTuple:
        private detail::OwningBase<TupleType>,
        public detail::MakeTupleTypeWithReferences<TupleType>::Type
    {
    private:
        typedef detail::MakeTupleTypeWithReferences<TupleType> BaseTypeBuilder;
        typedef typename BaseTypeBuilder::Type BaseType;
        typedef detail::OwningBase<TupleType> OwningBaseType;
    public:

        typedef typename BaseType::head_type head_type;
        typedef typename BaseType::tail_type tail_type;

    private:
        typedef TupleType OwnedTuple;

        OwnedTuple* getTuplePtr()
        {
            return this->tupleBuf.get();
        }
    public:
        // copy from other types of tuples too
        template<typename SomeTuple>
        OwningRefTuple(const SomeTuple& other):
            OwningBaseType(other),BaseType(BaseTypeBuilder::makeTuple(*getTuplePtr()))
        {
        }
        // copying copies values by default
        OwningRefTuple(const OwningRefTuple& other):
            OwningBaseType(other),BaseType(BaseTypeBuilder::makeTuple(*getTuplePtr()))
        {
        }

        // overload used for building the initial instance that references
        // data elsewhere
        template<typename SomeTuple>
        OwningRefTuple(SomeTuple& other,detail::PreserveReferences const&):
            BaseType(BaseTypeBuilder::makeTuple(other))
        {
        }

        // assignment assigns to referenced values
        template<typename SomeTuple>
        OwningRefTuple& operator=(const SomeTuple& other)
        {
            BaseType::operator=(other);
            return *this;
        }
        OwningRefTuple& operator=(const OwningRefTuple& other)
        {
            BaseType::operator=(other);
            return *this;
        }
    };

Anthony

-- 
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.

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