On Tue, Dec 10, 2013 at 10:43 AM, Andrey Semashev <andrey.semashev@gmail.com
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