Получить индекс типа boost::variant с помощью boost::mpl

boost::variant имеет элементы types, которые представляют собой структуру boost::mpl. Есть ли способ получить индекс типа в этой структуре во время компиляции, так что во время выполнения я мог бы сделать

if(myVariantInstance.which() == typeIndex)
{
   /*...*/
}

Вместо

if(myVariantInstance.type() == typeid(ConcreteType))
{
  /*...*/
}

person K117    schedule 04.06.2016    source источник
comment
Возможный дубликат boost::mpl::vector - получение базового смещения типа   -  person cha5on    schedule 08.06.2016
comment
@ cha5on, нет. Я сам потратил некоторое время на поиск решения и уже видел этот вопрос. С mpl::vector это работает как шарм, но с variant types он терпит неудачу с отсутствующим элементом pos для итератора типа. Рассмотрим этот (pastebin.com/Hd01nJQy) фрагмент, второй static_assert не работает.   -  person K117    schedule 08.06.2016
comment
Я понимаю, что вы имеете в виду, извините за путаницу.   -  person cha5on    schedule 10.06.2016


Ответы (3)


Это немного запутанно, и может быть лучший способ, но вы можете использовать boost::mpl::copy. Вот что должно работать, основываясь на примере из вашего комментария:

#include <boost/variant.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/vector.hpp>

typedef boost::mpl::vector<int, long, char> MyMplVector;
typedef boost::mpl::find<MyMplVector, long>::type MyMplVectorIter;
static_assert(MyMplVectorIter::pos::value == 1, "Error");

typedef boost::variant<int, long, char> MyVariant;
typedef boost::mpl::vector<> EmptyVector;
typedef boost::mpl::copy<
  MyVariant::types,
  boost::mpl::back_inserter<EmptyVector>>::type ConcatType;

typedef boost::mpl::find<ConcatType, long>::type MyVariantTypesIter;
static_assert(MyVariantTypesIter::pos::value == 1, "Error");
person cha5on    schedule 09.06.2016
comment
Спасибо. Это может быть полезно позже. На данный момент я реализовал is static_visitor следующим образом: pastebin.com/Pfn44GFf - person K117; 10.06.2016

Я нашел решение для получения индекса типа в boost::variant без boost::mpl, если вам это интересно.

#include <iostream>
#include <type_traits>

#include <boost/variant/variant.hpp>

using myvariant = boost::variant<int, bool, double, int>;

template <typename T, typename ... Ts>
struct type_index;

template <typename T, typename ... Ts>
struct type_index<T, T, Ts ...>
    : std::integral_constant<std::size_t, 0>
{};

template <typename T, typename U, typename ... Ts>
struct type_index<T, U, Ts ...>
    : std::integral_constant<std::size_t, 1 + type_index<T, Ts...>::value>
{};


template <typename T, typename ... Ts>
struct variant_first_same_type_idx;

template <typename T, typename Head, typename ... Tail>
struct variant_first_same_type_idx<T, boost::variant<Head, Tail ... >>
    : type_index<T, Head, Tail ...>
{};

int main()
{
    std::cout << variant_first_same_type_idx<int, myvariant>::value << std::endl;
    std::cout << variant_first_same_type_idx<bool, myvariant>::value << std::endl;
    std::cout << variant_first_same_type_idx<double, myvariant>::value << std::endl;
}

Вывод этой программы:

0
1
2
person Un1oR    schedule 15.12.2016

#include <boost/mpl/index_of.hpp>    
#include <iostream>

typedef boost::variant<int, std::string> VARIANT;
std::ostream &operator<<(std::ostream &_rS, const VARIANT&_r)
{    switch (_r.which())
     {    default:
             return _rS << "what the *";
          case boost::mpl::index_of<VARIANT::types, int>::type::value:
             return _rS << boost::get<int>(_r);
          case boost::mpl::index_of<VARIANT::types, std::string>::type::value:
             return _rS << boost::get<std::string>(_r);
     }
}

PS. Мне всегда было любопытно узнать о людях, использующих шаблон доступа посетителя...

ППС. Я знаю, что не нужно реализовывать оператор вывода, поскольку boost::variant уже предоставляет его - просто для пояснения...

person Frank Puck    schedule 01.04.2020