Boost logo

Boost :

Subject: Re: [boost] [variant] Warning: variadic templates in boost::variant
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2013-12-10 15:32:25


On Tue, Dec 10, 2013 at 10:43 AM, Andrey Semashev <andrey.semashev_at_[hidden]
> wrote:

> The problem is that, as opposed to union, variant provides advanced APIs
> which
> loose their meaning if no type is specified.

While that's true currently, I think that the issue is just the way in
which we have specified the requirements of a variant. In other words, it
was a design choice made early on because there wasn't a clear use-case for
variant<>. IMO, a variant<> is, as Peter also pointed out, analogous to
union {}, and I don't see anything logically wrong with such a construct.
I've also encountered the issue in practice so there is at least one
use-case.

> Making variant<> a special case
> with its own set of APIs makes generic programming more difficult since you
> have to propagate support for that special case through all surrounding
> templates.

I'm not sure I agree. It wouldn't have its own set of APIs. At most, it
would just be a subset of variant functionality (I.E. which() might not be
defined, or perhaps better, would be declared but either not be defined or
would static_assert if the definition were instantiated). If code you're
writing doesn't need to deal with the empty variant case, none of this
should be impacting you, you just personally have the requirement that the
number of types is >= 1 in your generic code, but for people that do need
to deal with it, they'd simply be using the subset of the API that makes
sense in their generic code. At this point in time, variant<> is just a
compile-error at the library-level, so users have to special-case if some
metaprogramming happens to results in a variant<>, regardless of what
trivial things they may attempt to do with it. Directly supporting
variant<> in a way that makes sense would eliminate the need for users to
do low-level special-casing.

Again, this isn't hypothetical. In practice I have encountered uses and the
existence of a variant<> would have just worked had it existed. For
instance, in the case I described in an earlier email, I had a "display"
visitor that displayed the contained object. In the empty case it made
sense for me to just do nothing. If variant<> were defined and
apply_visitor simply passed in an instance of some null tag type, it would
have been trivial for me to accomplish that without doing any
special-casing for the creation of the variant -- my visitor could have
just been defined to do nothing in that case. I wouldn't have had to
special case the creation of the variant. Further, I don't see how this
use-case is at-all unique and I wouldn't be surprised if others have
encountered situations where metaprogramming results in a variant<>.
Manually passing in a tag type when creating the variant in the case that
metaprogramming results in an empty sequence seems like a code smell to me.

If variant<> is really desired, it has to support all the APIs that are
> defined now for the non-empty variant. You can achieve that by making it
> always non-empty with a reasonable default, e.g.:
>
> template< typename T0 = blank, typename... TN >
> class variant;

Something like that may very well end up being the simplest solution and
I'd be in favor of a simple change such as that over the current state of
having variant<> be a compile error (similarly, make_variant_over with an
empty sequence should work...). I still think supporting an /actually/
empty variant might be better, but as long as there is some way to
logically represent variant<> and deal with it in generic code I'd
personally be satisfied.

-- 
-Matt Calabrese

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