【问题标题】:boost::variant and polymorphismboost::variant 和多态性
【发布时间】:2014-09-13 08:40:16
【问题描述】:

如果我将原始指针指向派生类,我想从 boost 变体中获取指向基类的指针。有没有办法实现这一点。以下代码不起作用。

class A{ public: virtual ~A(){}}; class B : public A{};
typedef boost::variant<A*,B*> MyVar;
MyVar var = new B;
A* a = boost::get<A*> (var); // the following line throws exception

也许有人知道如何编写我自己的 get 函数,该函数将测试请求的类型是否是变体中存储类型的基类,然后进行适当的转换

【问题讨论】:

    标签: c++ boost boost-variant


    【解决方案1】:

    您可以使用模板化的operator() 编写自己的访问者,如下所示:

    LIVE DEMO

    #include <iostream>
    #include <boost/variant.hpp>
    #include <type_traits>
    
    struct A { virtual ~A() {} virtual void foo() {} };
    struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
    
    template <typename T>
    struct visitor : boost::static_visitor<T>
    {
    private:
        using Base = typename std::remove_pointer<
                            typename std::remove_cv<
                                typename std::remove_reference<T>::type
                            >::type
                        >::type;
    
        template <typename U>
        T get(U& u, std::true_type) const
        {
            return u;
        }
    
        template <typename U>
        T get(U& u, std::false_type) const
        {
            throw boost::bad_get{};
        }
    
    public:
        template <typename U>
        T operator()(U& u) const
        {
            using Derived = typename std::remove_pointer<
                                typename std::remove_cv<
                                    typename std::remove_reference<U>::type
                                >::type
                            >::type;
    
            using tag = std::integral_constant<bool
                             , (std::is_base_of<Base, Derived>::value
                               || std::is_same<Base, Derived>::value)
                               && std::is_convertible<U, T>::value>;
    
            return get(u, tag{});
        }
    };
    
    template <typename T, typename... Args>
    T my_get(boost::variant<Args...>& var)
    {
        return boost::apply_visitor(visitor<T>{}, var);
    }
    
    int main()
    {    
        boost::variant<A*,B*> var = new B;
    
        A* a = my_get<A*>(var); // works!
        a->foo();
    
        B* b = my_get<B*>(var); // works!
        b->foo();
    }
    

    输出:

    B::foo()
    B::foo()
    

    问答部分:

    这个解决方案很奇怪!

    不,不是。这正是 Boost.Variant 中的访问者类的用途。 Boost.Variant 的最新版本中已经存在类似的解决方案,即boost::polymorphic_get&lt;T&gt;。遗憾的是,它是为其他目的而设计的,不能在这里使用。

    【讨论】:

    • 那个按钮将成为一个先例。对 coliru 没有运行我的大部分答案感到羞耻(太重了)
    • 这里的一个投票是为了标记世界上有多少人认为这是解决问题的方法。包括OP。
    • @SChepurin:欢迎提出您的解决方案
    • @Piotr S. - 我没有说你的解决方案不好。这简直是​​奇怪的解决方案。
    • @v.oddou "只有当内容是指定类型 U 或从类型 U 派生的类型时,该函数才会成功。这里 OP 将 pointers 存储在变体对象中。指针类型永远不会从任何其他类型派生。
    【解决方案2】:

    大家好,谢谢大家的回答和cmets 我来到以下内容,它在编译时决定类型是否相互继承。它似乎有效,而且对我来说似乎更容易理解。

     #include <iostream>
     #include <boost/variant.hpp>
     #include <boost/type_traits.hpp>
     #include <boost/utility.hpp>
    
     using namespace boost::type_traits;
    
    
     struct A { virtual ~A() {} virtual void foo() {} };
     struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
    
      typedef boost::variant<B*,A*,C*> MyVar;
    
    
    template <typename A,typename B> 
    struct types_are_inheritance_related
    { 
     static const bool value=     
     ice_or<
     boost::is_base_of<A, B>::value,
     boost::is_base_of<B, A>::value
     >::value;    
    };
    
    
     template<class Base>
     class get_visitor
    : public boost::static_visitor<Base*> { public:
    
    
    template<class T>
    Base* operator()( T* t, typename boost::enable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
    {
       Base* b = dynamic_cast<Base*> ( t);
       return b;           
    }  
    
    template<class T>
    Base* operator()( T* t, typename boost::disable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
    {       
       return 0;        
    }   
    };
    
    template<class T>
    T* get_var_value(MyVar& var)
    {
       get_visitor<T> visitor;
       T* aa= var.apply_visitor(visitor);
       return aa;
    }
    
    int main()
    {    
     MyVar var = new B;
    
     A* a = get_var_value<A*>(var); // works!
     a->foo();
    
     B* b = get_var_value<B*>(var); // works!
     b->foo();
    }
    

    【讨论】:

      猜你喜欢
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-05
      • 2014-04-25
      • 2011-06-22
      相关资源
      最近更新 更多