构造一个包含变体类型索引中第 n 个类型值的 boost 变体?

Posted

技术标签:

【中文标题】构造一个包含变体类型索引中第 n 个类型值的 boost 变体?【英文标题】:Construct a boost variant containing a value of the nth-type in the variant type index? 【发布时间】:2012-02-16 14:33:50 【问题描述】:

我想构造包含默认构造值的boost::variants,使用类型索引指定 - 无需在类型索引上编写我自己的 switch 语句。

我认为这必须以某种方式通过 MPL 实现?

为了澄清,索引不是编译时常量表达式。

用例是我需要构造一个变体,稍后将替换为包含正确值的变体,但此时我只知道类型索引。将其视为一个惰性反序列化问题。

【问题讨论】:

既然你提到了 MPL,我认为 N (类型索引)在编译时是已知的,但是惰性反序列化表明它可能只在运行时可用 --> 它是什么? @MatthieuM。后者是不可能的。我希望是第一个,否则我的答案也毫无价值。 @MatthieuM。啊,好点:它只在运行时可用。 @Autopulated 这是否为您赢得了“本月检查的最奇怪的代码”奖或为什么获得赏金? @pmr,事实上,我最终避免了创建空变体,这可能是明智的做法 - 我很感激你为解决我的疯狂问题付出的努力!跨度> 【参考方案1】:

您需要使用variant::types typedef。这为您提供了一个与 MPL 兼容的序列,然后我们可以将其与 mpl::at 和一个模板一起使用来进行我们的投标。这就是诀窍:

#include <string>
#include <boost/variant.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>

template<typename U, typename V>
void construct_in(V& v) 
  v = U();
  // modern
  // v = U;


int main()

  typedef boost::variant<int, std::string> variant;
  typedef boost::mpl::at<variant::types, boost::mpl::int_<1>>::type pos;
  variant v;
  // use type deduction
  construct_in<pos>(v);
  // does not throw, does work
  std::string& s =boost::get<std::string>(v);
  return 0;

运行时变体如下:

#include <string>
#include <vector>
#include <functional>

#include <boost/variant.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/for_each.hpp>

typedef boost::variant<int, std::string> variant;
typedef variant::types types;
typedef std::vector< std::function<void(variant&)> > fvec;

template<typename U, typename V>
void construct_in(V& v) 
  v = U;


struct build_and_add 
  fvec* funcs;
  template<typename T>
  void operator()(T) 
    funcs->push_back(&construct_in<T, variant>);
  
;


int main()


  variant v;
  std::vector< std::function<void(variant&)> > funcs;

  // cannot use a lambda, would need to be polymorphic
  build_and_add f = &funcs;
  boost::mpl::for_each<types>(f);

  // this is runtime!
  int i = 1;

  funcs[i](v);
  // does not throw, does work
  std::string& s =boost::get<std::string>(v);
  return 0;

这有点神秘,需要使用可变参数进行一些调整 参数是真正通用的,但它会做你想要的。其他人需要弄清楚这是否会导致显着 代码爆炸。

【讨论】:

很抱歉澄清类型索引是运行时的,但我认为这个答案没有用 - 可以扩展它以在运行时在 N 个常量索引之间切换,其中只有 N 在编译时是固定的(甚至可以从变体中提取出来,也许?) @Autopulated 不是真的,但一些黑魔法可能会有所帮助。想想我们用于构建的模板。我们可以在编译时生成所有这些模板,并将它们作为std::function 对象存储在一个向量中,并在运行时使用这个向量来查找我们想要构建的内容。我会尝试把一些东西放在一起,但我不知道在代码爆炸等方面会有多好。 @pmr:我的下意识反应是使用递归,但是指向函数的向量(或数组,因为 N 是常数)似乎提供了更好的性能保证(不依赖于最终的尾递归)。您可能仍然需要递归来初始化向量,但它是一次性的。 @MatthieuM。对于这些事情,我是mpl::for_each 的忠实粉丝。使用 MPL 编写递归模板函数总是有点棘手,因为它们的序列不是真正的可变参数模板。 @MatthieuM。我更喜欢临时函子的引用指针,消除了对构造函数的需要。关于订单:我找不到任何明确的内容,但for_each 最多需要ForwardSequence,因此不应允许它做任何其他事情。

以上是关于构造一个包含变体类型索引中第 n 个类型值的 boost 变体?的主要内容,如果未能解决你的问题,请参考以下文章

如何构造一个包含多种数据类型值的字节数组?

切片时返回错误索引值的数据类型

OCaml 错误:“变体类型没有构造函数 ::”

python面试题-输入一个由n个大小写字母组成的字符,按Ascii码值从小到大排序,查找字符串中第k个最小Ascii码值的字母

查找列表中第 n 个项目的索引

利用正则来查找字符串中第n个匹配字符索引