From: Itay Maman [mailto:itay_maman@yahoo.com]
Sent: 09 August 2002 12:31
> Anthony Williams wrote in a message:
> >
> >I've just had a thought about how to implement the strong
> guarantee for
> variant, at the expense of larger space requirements --- have
> *two* copies
> of >the internals, with a flag to indicate which is valid. Then, when
> swapping or assigning, copy construct the value from the
> other variant into
> the unused >space, and destruct the original and switch the flag when
> everything is done.
>
> I don't think it is possible - in the general case - to
> create two identical
> instances of a class.

Sorry, that's not what I meant. The variant would have _storage_ for two instances, but only contain one at a time. When swapping the variants, you can copy-construct the other variant into the unused space in this variant, then copy-construct this variant into the unused space in the other one. If everything has succeeded, destruct the originals, and change the flags. If anything failed, destruct the new copies (if any) and leave the flags alone.

Simple example, with a known type (untested):

class X{};

class Y
{
        char buf1[sizeof(X)]; // ignoring alignment
        char buf2[sizeof(X)];
        bool useBuf1;
       
        X& getVal()
        {
                if(useBuf1)
                {
                        return *reinterpret_cast<X*>(buf1);
                }
                else
                {
                        return *reinterpret_cast<X*>(buf2);
                }
        }
public:
        Y(const X& val):useBuf1(true)
        {
                new (buf1) X(val);
        }

        ~Y()
        {
                getVal().~X();
        }

        void swap(Y& other)
        {
                // copy the other into this one
                if(useBuf1)
                {
                        new (buf2) X(other.getVal());
                }
                else
                {
                        new (buf1) X(other.getVal());
                }

                // now copy this into the other
                try
                {
                        if(other.useBuf1)
                        {      
                                new (other.buf2) X(getVal());
                        }
                        else
                        {
                                new (other.buf1) X(getVal());
                        }
                }
                catch(...)
                {
                        // destroy already-created copy
                        useBuf1=!useBuf1;
                        getVal().~X();
                        useBuf1=!useBuf1;
                        throw;
                }

                // OK, both copies succeeded, so destroy originals
                // and change flags
                getVal().~X();
                useBuf1=!useBuf1;
                other.getVal().~X();
                other.useBuf1=!other.useBuf1;
        }

        Y& operator=(const Y& other)
        {
                // create a copy
                if(useBuf1)
                {
                        new (buf2) (other.getVal());
                }      
                else
                {
                        new (buf1) X(other.getVal());
                }

                // if that succeeded, destroy our original, and flip flag.
                getVal().~X();
                useBuf1=!useBuf1;              

                return *this;
        }
};


Obviously, you need to account for alignment, and with variant it is a bit more complex in the implementation due to the multiple types, but the idea is the same.

Also, if you want assignment to actually perform assignment on the underlying type, rather than just transfer the value into the variant, then things are more complicated.

Anthony