【问题标题】:How do I get the `.which()` of a particular type in a boost::variant?如何在 boost::variant 中获取特定类型的 `.which()`?
【发布时间】:2014-11-20 17:08:05
【问题描述】:

说我有:

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++ templates boost variant


    【解决方案1】:

    如果你可以使用 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
    

    Demo.

    【讨论】:

    • 该死的,太激烈了……谢谢!这将适用于 linux,但它是一个跨平台项目,我在 Windows 上使用 MSVC 2012,我认为至少不会喜欢 using find = find_ ... 行。
    • @Claudiu 如有必要,您可以将别名模板替换为类模板。
    • 看起来我的小狗踩到了我的键盘:D +1,顺便说一句
    【解决方案2】:

    既然你已经在使用 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 而不是 typessequence 的最后一个索引,这显然是更好的事情:

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

    【讨论】:

    • 这很酷,但是如果一个类型不可用,它会简单地显示最后一个位置,但是可以修复,我试过this,也必须是一些简单的编码。
    • 但这不是编译时解决方案。
    • @IgorR。可以发constexpr.
    • @IgorR.I 使用了 OP 想要的格式,它是一个简单的模板函数,但它可以成为 c++11 中的模板结构 typedef 或模板化类型别名,用于编译时检查因为这里的一切在编译时都是已知的
    • @P0W 谢谢,如果操作人员要求,我正在考虑改进它:)
    猜你喜欢
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 2013-08-03
    • 2022-07-08
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多