Domanda

I need to create an union, but 2 members of the union would have the same type, thus I need a way to identify them. For example in OCaml :

type A = 
  | B of int
  | C of float
  | D of float

Boost.Variant doesn't seem to support this case, is there a known library which supports that ?

È stato utile?

Soluzione

If you want to do this, I think your best option is to wrap the same-but-different-types into a struct which then lets the boost variant visit the proper one:

struct Speed
{
    float val_;
};

struct Darkness
{
    float val_;
};

You might be able to use BOOST_STRONG_TYPEDEF to do this automatically but I'm not sure it's guaranteed to generate types legal for use in a union (although it would probably be fine in a variant).

Altri suggerimenti

You cannot at the moment but C++17's implementation of std::variant fortunately allows it:

A variant is permitted to hold the same type more than once, and to hold differently cv-qualified versions of the same type.

Unlike with the boost version, you can get values by index, something like this (not tested):

// Construct a variant with the second value set.
variant<string, string, string> s(std::in_place_index<1>, "Hello");
// Get the second value.
string first = std::get<1>(s);

Michael Park has written a C++14 implementation of C++17's std::variant.

The c++ code here:

http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_storage/pack/container_one_of_maybe.hpp

is truly a tagged union in that it can contain duplicate types. One nice feature is the tags can be enumerations; hence, the tags can have meaningful names.

Unfortunately, the compile time cost is pretty bad, I guess, because the implementation uses recursive inheritance. OTOH, maybe compilers will eventually figure out a way to lessen the compile time cost.

OTOH, if you want to stick with boost::variant, you could wrap the types, as Mark B suggested. However, instead of Mark B's descriptive class names, which require some thought, you could use fusion::pair<mpl::int_<tag>,T_tag> where T_tag is the tag-th element in the source fusion::vector. IOW:

variant
< fusion::pair<mpl::int_<1>,T1>
, fusion::pair<mpl::int_<2>,T2>
...
, fusion::pair<mpl::int_<n>,Tn>
>

As the fusion docs:

http://www.boost.org/doc/libs/1_55_0/libs/fusion/doc/html/fusion/support/pair.html

say, fusion::pair only allocates space for the 2nd template argument; hence, this should not take any more room than boost::variant<T1,T2,...,Tn>.

HTH.

-regards, Larry

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top