在C++中多次标记具有相同类型的并集(又称变体)

Tagged unions (aka variant) in C++ with the same type multiple times

本文关键字:又称 同类型 C++      更新时间:2023-10-16

我需要创建一个联合,但联合的两个成员将具有相同的类型,因此我需要一种方法来识别它们。例如OCaml:

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

Boost.Variant似乎不支持这种情况,有已知的库支持吗?

如果你想做到这一点,我认为你最好的选择是将相同但不同的类型封装到一个结构中,然后让boost变体访问正确的类型:

struct Speed
{
    float val_;
};
struct Darkness
{
    float val_;
};

可能能够使用BOOST_STRONG_TYPEDEF自动执行此操作,但我不确定它是否能保证生成在联合中合法使用的类型(尽管在变体中可能会很好)。

目前还不能,但幸运的是,C++17对std::variant的实现允许它:

一个变体可以多次持有同一类型,也可以持有相同类型的不同cv限定版本。

与boost版本不同,您可以通过索引获取值,类似于以下内容(未测试):

// 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编写了C++17的std::variant的C++14实现。

此处的c++代码:

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

是一个真正的标记并集,因为它可以包含重复的类型。一个不错的功能标签可以是枚举;因此,标签可以具有有意义的名称。

不幸的是,我想编译时间成本相当高,因为实现使用递归继承。OTOH,也许编译器最终会找到一种方法以减少编译时间成本。

OTOH,如果你想坚持使用boost::变体,你可以包装类型,正如马克B所建议的那样。然而与Mark B的描述性类名不同,需要一些思考,可以使用fusion::pair<mpl::int_<tag>,T_tag>其中CCD_ 5是源CCD_。IOW:

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

作为融合文档:

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

例如fusion::pair只为第二个模板参数分配空间;因此这不应该占用比CCD_ 8更多的空间。

HTH。

-问候,Larry

相关文章: