Boost logo

Boost :

From: Eric Friedman (ebf_at_[hidden])
Date: 2002-08-11 02:31:13


Quoting Douglas Gregor <gregod_at_[hidden]>:
> On Saturday 10 August 2002 10:02 am, David Abrahams wrote:
> > IIUC, Howard's idea of move semantics either constructs or assigns
> > a T, leaving a valid but possibly changed T behind in the source
> > object.
> >
> > POD types, for example, are trivially-movable.
>
> Yes, I think this is exactly what we need.
[snip]

Introducing move semantics is all-good and well, and I think it's
something Boost should "standardize" anyway, but I think we also need
to figure out a good way to keep the non-empty invariant for
boost::variant -- even when its bounded types do not provide the
nothrow-move guarantee.

So far, this list has been presented with two possibilities to maintain
the non-empty invariant for all variants bounding *any* type:
  1) heap-allocation
  2) Anthony William's double-storage proposal, at:
       http://aspn.activestate.com/ASPN/Mail/Message/boost/1314807

Now it's obvious that #1 isn't really what we want, for it just
transforms boost::variant into a stricter, more typesafe boost::any --
without any of the efficiency gains of a stack-allocated solution.

On the other hand, #2 strikes me as a rather ingenious solution --
perhaps even as a general idiom. But then there is the (potentially
significant) storage overhead....

So let me propose what I see as the best solution for the Boost.Variant
library. There would be two types, boost::variant and
boost::safe_variant. (And of course, C++0x template typedefs could
separate the two by a policy specified for a
boost::configurable_variant, but let's not go there until template
typedefs come to us...)

boost::variant would not maintain the non-empty invariant in general.
Indeed, it would look much like the variant implementation now in the
sandbox, plus support for some kind of move semantics. Thus, it would
be *capable* of maintaing the non-empty invariant if all of its types
provide *nothrow* move semantics. As well, the variant could take care
of special cases, such as boost::incomplete types, which can be moved
safely -- even if not through traditional move semantics.

boost::safe_variant, on the other hand, would use the double-storage
proposal for each bounded type that does not provide nothrow-move
semantics. Thus the maximum sizeof as a safe_variant's storage _could_
be twice that of a plain variant. But in cases where all of
safe_variant's types are "safe" (i.e. provide nothrow-move), a
safe_variant would not be any less efficient than an "unsafe" variant.

A second on naming: I use the names boost::variant and
boost::safe_variant, but it may be a better idea to reverse them. That
is, it might be better to make boost::variant the class that is "safe"
for any types, and to include something like a boost::small_variant for
those users who care more about space than they do about variant's
invariants.

I think the most important point, however, to draw from the proposal is
that the two classes would really be one and the same if the set of
bounded types provides nothrow-move semantics. It's just that in
generic programming situations, where the types bounded by a variant
may not be known at the time of authoring, *safe_variant would
guarantee the non-empty invariant whereas small_variant would not*.
This is the fundamental difference between the two types, and I think
this difference is significant enough to warrant the inclusion of these
two different 'kinds' of variant.

Let me know what you think.

Thanks,
Eric


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