On Mon, Dec 9, 2013 at 12:28 PM, Peter Dimov
Steven Watanabe wrote:
The difference between tuple<> and variant<> is that tuple<> has exactly one possible value, but variant<> has no possible values.
Not conceptually. tuple
is struct { X x; Y y; }. variant is union { X x; Y y; }. tuple<> is struct {}. variant<> is union {}. All are valid. It's not that important though. The current variant doesn't support this case, so there's not much reason for the variadic one to do so. Sorry for bringing it up.
I'm going to have to back you up here that a variant<> does sometimes make sense and I don't think we'd lose anything by supporting it. In real, non-hypohetical code, I've encountered a place where I had a 0-element variant come up and had to special-case my code so that it would work as expected. The way it came up was I had a variant of several types (the type list was the result of some metaprogramming) and a visitor of that variant that returned the result of a member function call on the currently stored object, whichever one it was (each type in the variant had the same named function but the return type wasn't necessarily the same). I constructed the return type based on the return types of the functions in question, eliminating any duplicates. If one of the functions returned a void type, no type was added to the list. I stored this result and later on did things with it (such as display it). What this meant in practice was that I was sometimes left with 0-element and 1-element variants. It would be nice if the 0 case just worked as expected rather than having to special-case. As well, in the case of a single-element variant, it would be nice if the ID weren't explicitly stored since it would always be the same value (I don't remember if Boost.Variant makes this optimization). If there is some ambiguity with how a 0-element variant should be handled, then I'd say perhaps we should leave it as a compile-time error, but I think that in practice you'd just expect it to be a stateless type that either always does nothing when visited, passes some kind of special tag type when visited (this might be better since it would work with n-ary visitation), or simply produces a compile-time error when visited. I don't know what this means with respect to Variant's "never-empty" guarantee or the result of .empty(), but intuitively I'd just say that a variant satisfies the never-empty guarantee iff the amount of types it is over is greater than 0. In the 0 case, empty() would return false (it should also be static constexpr in any case). -- -Matt Calabrese