2014-09-13 3 views
7

Я хочу получить указатель на базовый класс из варианта boost, если я поставлю orignally указатель на производный класс. Есть ли способ достичь этого. Следующий код не работает.boost :: variant and polymorphism

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 

Может быть кто-то есть идеи, как написать свою собственную функцию ПОЛУЧИТЬ, которая будет проверять, если запрашиваемый тип базового класса хранимого типа в варианте, а затем делать соответствующий CAST

ответ

2

Привет, спасибо всем за ваши ответы и комментарии Я пришел к следующему, который решает во время компиляции, если типы наследуются друг от друга. И, похоже, это работает, и мне кажется намного легче понять.

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

Вы можете написать собственный посетитель с шаблонным 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() 

Q & Раздел:

Это решение странно!

Нет, это не так. Это именно то, что посещают классы в Boost.Variant для. Подобное решение уже существует в последнем выпуске Boost.Variant, который является boost::polymorphic_get<T>. К сожалению, он был разработан для других целей и не может быть использован здесь.

+0

Эта кнопка станет прецедентом. Позор о том, что coliru не работает большинство моих ответов (слишком тяжелый) – sehe

+0

Один голос здесь, чтобы отметить количество людей в мире, думая, что это способ приблизиться к проблеме. Включая OP. – SChepurin

+0

@ Щепурин: не стесняйтесь представить свое решение –

Смежные вопросы