Boost logo

Boost :

Subject: Re: [boost] [variant] match()
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2015-01-09 17:05:31


On Fri, Jan 9, 2015 at 1:24 PM, Larry Evans <cppljevans_at_[hidden]>
wrote:

> Which seems simpler to me. After all, implementing the
>
discriminated union involves, at first, just the "primitives":
>

I've implemented variant on top of discriminated_union and I've implemented
discriminated_union on top of variant. To be honest, both solutions leave a
lot to be desired although neither is particularly difficult to do. The
types I actually use aren't built on one another, but are built on shared,
lower-level constructs.

   1) calculating the size an alignment of a buffer
>

You actually don't do this when implementing a discriminated union type
(nor variant) anymore. You need to use an *actual* union underneath the
hood in order for some degree of constexpr-ness in places that it is
possible. This is one reason for the union_ and destructible_union
templates in my earlier reply (they use a cons-like recursive union
structure underneath the hood, which is an approach that Eric Niebler
suggested and that I've seen done elsewhere as well). They are necessary as
implementation details and useful on their own when discrimination isn't
required. They support fully forwarded construction of the members along
with access by index, etc.

   2) using the tag to find the right type in a type list as
> in the mpl::at_c<tag>:
>
> Using variant, step 1 is the same, but how is step 2
> implemented?

I'm sure you are making a good point but I'm having trouble understanding
what specifically you are saying here. To be clear, I agree that in theory
it makes more sense to implement variant on top of discriminated_union, but
having implemented each on top of the other in the past, they both have
different problems, though neither is too difficult to do and you don't
lose any functionality. It just ends up being that the implementation still
has some complexities and the compile-times take a noticeable hit, so
building them each from exactly their shared requirements ends up working
better.

> Could you describe the lower-level primitives?

The union_ and destructible_union templates, along with an unfortunately
complicated set of chained CRTP bases that are required to guarantee that
each of the special member functions are individually declared and defined
(and possibly trivial) exactly when they can be. I didn't elaborate
earlier, but the reason destructible_union exists is because with the way
C++ union rules are, if any of the members has a destructor that is
non-trivial, the overall union itself is not descructible at all. This
"not-defined-if-any-are-nontrivial" is true of all of the special member
functions with respect to modern unions, but allowing destructibility is
important here because while you can encapsulate a type that is, for
instance, not copyable, and then give the containing type a copy
constructor, you cannot encapsulate a type that is not destructible and
then give the containing type a destructor. Instead, the union itself needs
to be destructible. So, destructible_union is equivalent to union_ in cases
where all of the destructors were trivial, but in the case that any of them
are not trivial, it defines its own destructor that does nothing. This way
it can be used when implementing a variant or a discriminated_union (or
other constructs).

-- 
-Matt Calabrese

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