Eric Friedman wrote: [snip] > ...there are alternative (albeit less elegant) options. [snip]
I'd like to present what are IMO the most viable options for manually disabling variant's double storage. Option #1: (I presented a very similar strategy to this some time ago at http://aspn.activestate.com/ASPN/Mail/Message/1316541, but I called it small_variant at the time.) Designate void as a flag that signals to variant to disable the double storage technique. That is, variant<T1, ..., void, ..., TN> will always operate with single storage. Of course, as I discussed in my previous message, this means that a failed assignment/swap may result in an 'uninitialized' state for these variants since void is not a meaningful type of content. Any variant in such an uninitialized state will be called 'singular.' The *only* valid operations on a singular variant are variant::operator=, variant::~variant, and the variant 'query' methods (i.e., which, empty, and type). The semantics of the query operations will change for singular variants: variant::which will return -1, variant::empty will return true, and variant::type will return typeid(void). Note that under this option, boost::empty would still be usable in variant, but only in a generic fashion. That is, boost::empty would simply exist as a convenience, and no special status would be conveyed to variant<T1, ..., boost::empty, ..., TN>. If we ultimately adopt this option, we might even seek another name for boost::empty to avoid confusion. Option #2: Designate boost::empty as a flag to disable the double storage technique. Like option #1 above, variant<T1, ..., boost::empty, ..., TN> will always operate with single storage. However, unlike option #1 above, any failed assignment/swap may result in the construction of boost::empty content in its place. The advantage of this approach is that there are no messy unitialized states and no singular variants. All operations on variants are always well-defined. The disadvantage of this approach is that while boost::empty is an otherwise perfectly typical type, its use in a variant will dramatically alters the variant's semantics, a point which may not be immediately clear to unsuspecting users. A third point, which is a mixed bag, is that all visitors to such variants will need to explicitly handle boost::empty as a possible type of content. Certainly, this is an advantage in terms of type safety. But it may be a nuisance to those users who want to simply ignore the possibility of an empty variant -- except in the immediate aftermath of a failed assign/swap. I imagine option #1 would appeal to these users. Option #3: Provide both option #1 and option #2. Naturally, this introduces all the advantages and disadvantages of the two options, which may be a good thing in terms of flexibility. Of course, it complicates the semantics of using variant even further. --- Finally, I'd like to extend one warning against all of the above options, as well as any other proposal that selectively abandons the double storage technique. Namely, there may arise some situations in generic code where such customizability of variant's exception safety guarantees (or invariants, if you wish to see the matter in that light) will result in semantics unanticipated by either the generic algorithm author or client. Quite frankly I can't imagine any such situations, but I don't believe the limited extent of my imagination should assure many <g>. As always, I'd appreciate feedback on this (unfortunately long) message. Thanks, Eric _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost