
I have a situation where I have a class that stores two mutually exclusive optional values. This results in double overhead of two bools and twice the "reserved" space. I could opt for a boost::optional<boost::variant<A,B> >, but this would incur extra costs associated with the implementation of boost::variant. Considering the fact that boost::variant<> explicitly guarantees to be always "valid", it seems like it would be reasonable to have boost::optional<A,...> that behaves like boost::variant<>, yet is optimized specifically for allowing "empty" states as well. The boolean could then become the type index where 0 is empty, 1 is A, 2 is B etc. Thoughts? Dan

On 4 March 2010 00:48, Daniel Larimer <dlarimer@gmail.com> wrote:
I have a situation where I have a class that stores two mutually exclusive optional values. This results in double overhead of two bools and twice the "reserved" space. I could opt for a boost::optional<boost::variant<A,B> >, but this would incur extra costs associated with the implementation of boost::variant. Considering the fact that boost::variant<> explicitly guarantees to be always "valid", it seems like it would be reasonable to have boost::optional<A,...> that behaves like boost::variant<>, yet is optimized specifically for allowing "empty" states as well.
The boolean could then become the type index where 0 is empty, 1 is A, 2 is B etc.
It seems like boost::variant is already 99% of the way there. "So as to make the behavior of variant more predictable in the aftermath of an exception, the current implementation prefers to default-construct boost::blank if specified as a bounded type instead of other nothrow default-constructible bounded types." ~ http://www.boost.org/doc/libs/1_42_0/doc/html/variant/design.html#variant.de... With that, I think you might get almost exactly what you want just by changing v.empty() to be v.operator==(boost::blank()) instead of always false and adding a few convenience functions.

On Wed, Mar 3, 2010 at 10:48 PM, Daniel Larimer <dlarimer@gmail.com> wrote:
I have a situation where I have a class that stores two mutually exclusive optional values. This results in double overhead of two bools and twice the "reserved" space. I could opt for a boost::optional<boost::variant<A,B> >, but this would incur extra costs associated with the implementation of boost::variant. Considering the fact that boost::variant<> explicitly guarantees to be always "valid", it seems like it would be reasonable to have boost::optional<A,...> that behaves like boost::variant<>, yet is optimized specifically for allowing "empty" states as well.
The boolean could then become the type index where 0 is empty, 1 is A, 2 is B etc.
I actually do just use variant directly: boost::variant<unused,A,B> Unused is used in spirit/phoenix/etc... and is completely empty, takes no space, default constructable, etc... And if the id of the variant tests 0, it is unused, so it is a simple bool test to that value.

On 03/03/10 23:48, Daniel Larimer wrote:
I have a situation where I have a class that stores two mutually exclusive optional values. This results in double overhead of two bools and twice the "reserved" space. I could opt for a boost::optional<boost::variant<A,B> >, but this would incur extra costs associated with the implementation of boost::variant. Considering the fact that boost::variant<> explicitly guarantees to be always "valid", it seems like it would be reasonable to have boost::optional<A,...> that behaves like boost::variant<>, yet is optimized specifically for allowing "empty" states as well.
The boolean could then become the type index where 0 is empty, 1 is A, 2 is B etc.
http://www.boostpro.com/vault/index.php?&directory=Data%20Structures contains composite_tagged_seq.zip which contains a template, composite_tagged_seq, which can be used as follows to satisfy your requirements: using namespace boost::composite_tags; using namespace boost::mpl; typedef composite_tagged_seq < one_of_maybe , integral_c<int,1> , vector<A,B> > a_or_b_maybe_t; a_or_b_maybe_t a_or_b_maybe_v; BOOST_ASSERT(( a_or_b_maybe_v.which() == 0 )); a_or_b_maybe_v.inject<1>(A()); BOOST_ASSERT(( a_or_b_maybe_v.which() == 1 )); A* a_ptr=a_or_b_maybe.project<1>(); BOOST_ASSERT(( a__ptr )); B* b_ptr=a_or_b_maybe.project<2>(); BOOST_ASSERT(( !b__ptr )); Of course one problem with this compared with variant<unused,A,B> is that it requires: 1) the extra template parameters, one_of_maybe and integral_c. 2) the more verbose inject<1>(A()) instead of directly assigning from A(). 3) the more verbose project<1>() instead of directly assigning to an A *and* checking the nullness of the result. OTOH, one advantage is that A and B can be the same type. This may not be useful in your case; however, it more closely reflects a disjoint union: http://en.wikipedia.org/wiki/Disjoint_union which is useful in representing the output of a lexical analyzer. For example, each keyword in a language would have an unused type and the lexical analyzer only needs to indicate which keyword (i.e. the value of the "type index", in your words) was found. HTH. -regards, Larry
participants (4)
-
Daniel Larimer
-
Larry Evans
-
OvermindDL1
-
Scott McMurray