Создать вариант наддува, содержащий значение n-го типа в индексе типа варианта? - PullRequest
9 голосов
/ 16 февраля 2012

Я хочу создать boost::variant s, содержащие значения по умолчанию, заданные с помощью индекса типа - без записи собственного оператора switch над индексом типа.

Я полагаю, это должно быть как-то возможно с MPL?

Для пояснения, индекс не является константным выражением во время компиляции.

Вариант использования: мне нужно создать вариант, который позже будет заменен вариантом, содержащим правильное значение, но на данный момент я знаю только индекс типа. Думайте об этом как о ленивой проблеме десериализации.

1 Ответ

13 голосов
/ 16 февраля 2012

Вам нужно использовать 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;
}

Это немного загадочно, и нужно немного подправить вариадику. Аргументы должны быть действительно общими, но они делают то, что вы хотите. Кто-то еще должен выяснить, приводит ли это к значительному код взрыва.

...