如何在 boost::variant 中获取特定类型的“.which()”

How do I get the `.which()` of a particular type in a boost::variant?

本文关键字:类型 which boost variant 获取      更新时间:2023-10-16

假设我有:

typedef boost::variant<int, float, std::string> moog;

给定一个moog实例,我可以获取其类型的.which(),例如:

moog foo = ...;
foo.which(); //0 for int, 1 for float, 2 for std::string

给定类型本身获取.which()的最佳方法是什么?例如:

moog.MAGIC<int>(); // 0
moog.MAGIC<float>(); // 1
moog.MAGIC<std::string>(); // 2

我想我可以实例化一个moog并以这种方式执行此操作(未经测试,仅示例):

template <class Variant, class Which>
size_t MAGIC() {
    Which w;
    Variant foo = w;
    return foo.which(); 
}
MAGIC<moog, int>(); // 0
MAGIC<moog, float>(); // 1
MAGIC<moog, std::string>(); // 2

但是,这很笨拙,因为它需要实例化两个对象。它也适用于没有默认构造函数的类。

如果可以使用 C++11:

template <std::size_t, typename, typename...> struct find_;
template <std::size_t pos, typename T, typename Other, typename... Args>
struct find_<pos, T, Other, Args...> : find_<pos+1, T, Args...> {};
template <std::size_t pos, typename T, typename... Args>
struct find_<pos, T, T, Args...> : std::integral_constant<std::size_t, pos> {};
template <std::size_t pos, typename T>
struct find_<pos, T> : std::integral_constant<std::size_t, std::size_t(-1)> {};
template <typename T, typename... Args>
using find = find_<0, T, Args...>;
template <typename, typename> struct IndexInVariant;
template <typename T, typename... Types>
struct IndexInVariant<boost::variant<Types...>, T> :
    find<typename std::remove_cv<T>::type, Types...> {};

用法:

IndexInVariant< boost::variant<int, float, std::string>, std::string >::value // 2
IndexInVariant< boost::variant<int, float, std::string>, char >::value // -1

演示

既然你已经在使用boost,你不妨使用boost::mpl

#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/find.hpp>
template <class Variant, class Which>
size_t MAGIC()
{
  return boost::mpl::distance
         <typename boost::mpl::begin<typename Variant::types>::type,
          typename boost::mpl::find<typename Variant::types, Which>::type
         >::type::value;
}

编辑

P0W 提出了一个版本,如果未找到类型,则返回 -1,而不是types序列的最后一个索引,这显然是一件更好的事情:

template <class Variant, class Which>
int MAGIC()
{
  size_t pos = boost::mpl::distance
         <typename boost::mpl::begin<typename Variant::types>::type,
          typename boost::mpl::find<typename Variant::types, Which>::type
         >::type::value ;
  size_t last= boost::mpl::distance
         <typename boost::mpl::begin<typename Variant::types>::type,
          typename boost::mpl::end<typename Variant::types>::type
         >::type::value;
         return pos != last ? pos : -1 ;
}