使用 boost::mpl 获取 boost::variant 的类型索引

Posted

技术标签:

【中文标题】使用 boost::mpl 获取 boost::variant 的类型索引【英文标题】:Get boost::variant's type index with boost::mpl 【发布时间】:2016-06-04 05:00:50 【问题描述】:

boost::variant 有成员 types 这是某种 boost::mpl 结构。 有没有办法在编译时获取该结构中的类型索引,所以在运行时后期我可以这样做

if(myVariantInstance.which() == typeIndex)

   /*...*/

代替

if(myVariantInstance.type() == typeid(ConcreteType))

  /*...*/

【问题讨论】:

boost::mpl::vector - getting to a type's base-offset的可能重复 @cha5on,不。我花了一些时间自己寻找解决方案,并且已经看到了这个问题。使用mpl::vector 它就像一个魅力,但使用varianttypes 它失败,因为缺少类型迭代器的pos 成员。考虑这个 (pastebin.com/Hd01nJQy) sn-p,第二个 static_assert 失败。 我明白你的意思,很抱歉造成混乱。 【参考方案1】:

如果您有兴趣,我找到了在没有 boost::mpl 的情况下在 boost::variant 中获取类型索引的解决方案。

#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

【讨论】:

【参考方案2】:

这有点复杂,可能有更好的方法,但你可以使用 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");

【讨论】:

谢谢。以后可能会有用。现在我像这样实现isstatic_visitor:pastebin.com/Pfn44GFf【参考方案3】:
#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。我一直对使用访问者访问模式的人感到好奇...

PPS。我知道不需要实现输出运算符,因为 boost::variant 已经提供了一个 - 仅用于解释目的......

【讨论】:

以上是关于使用 boost::mpl 获取 boost::variant 的类型索引的主要内容,如果未能解决你的问题,请参考以下文章

boost::mpl::apply 仅适用于类型化模板参数

boost::mpl::eval_if的使用方法

利用 boost-variant 创建带有 boost::mpl::for_each 的通用工厂方法

Boost mpl::list 变体序列化 check_const_loading() 编译错误

是否可以在运行时迭代 mpl::vector 而不实例化向量中的类型?

Sun C++ 编译器和 Boost