Boost :: variant and polymorphism

I want to get a pointer to a base class from the boost option if I put an orignally pointer to a derived class. Is there any way to achieve this. The following code does not work.

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 

Maybe someone has an idea how to write my own get function, which will check if the requested type is the base class of the stored type in this option, and then do the corresponding listing

+7
c ++ boost boost-variant
source share
2 answers

Hi everyone, for your answers and comments, I came to the following, which decides at compile time if types are inherited from each other. And it seems to work, and it seems a lot easier for me to understand.

  #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(); } 
+2
source share

You can write your visitor with the operator() pattern as shown below:

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

Output:

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

Section Q and A:

This decision is strange!

No, it is not. This is exactly what visitor classes in Boost.Variant are for. A similar solution already exists in the latest version of Boost.Variant, which boost::polymorphic_get<T> . Unfortunately, it was designed for other purposes and cannot be used here.

+9
source share

All Articles