Construct a boost variant containing a value of the nth-type in the variant type index?

你说的曾经没有我的故事 提交于 2019-12-09 15:39:49

问题


I want to construct boost::variants containing default-constructed values, specified with a type index - without writing my own switch statement over the type index.

I figure this must be possible, somehow, with MPL?

To clarify though, the index is not a compile-time constant expression.

The use case is that I need to construct a variant which will later be replaced with one containing the correct value, but at this point I only know the type index. Think of it as a lazy deserialisation problem.


回答1:


You need to use the variant::types typedef. This gives you an MPL compatible sequence which we can then use with mpl::at and a template to do our bidding. This does the trick:

#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;
}

Here goes the runtime-variant:

#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;
}

It's a little arcane and will need some tweaking with variadic arguments to be truly generic, but it does what you want. Someone else needs to figure out if this results in significant code blow-up.



来源:https://stackoverflow.com/questions/9313108/construct-a-boost-variant-containing-a-value-of-the-nth-type-in-the-variant-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!