boost::变体和多态性

boost::variant and polymorphism

本文关键字:多态性 boost      更新时间:2023-10-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函数,该函数将测试请求的类型是否是变体中存储类型的基类,然后进行适当的转换

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

现场演示

#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()

Q&A部分:

这个解决方案很奇怪

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

嗨,谢谢大家的回答和评论我得出了以下结论,即在编译时决定类型是否相互继承。它似乎起了作用,对我来说似乎更容易理解。

 #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();
}