Возможно, я неправильно понимаю вопрос, но если вы хотите использовать тот же variant_visitor
для варианта, содержащего общие указатели вместо простых указателей, возможно, это может быть достигнуто с другим посетителем, который получает указатель из shared_ptr
и передает его другому посетителю.
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef boost::shared_ptr<Base> base_ptr;
typedef boost::variant<boost::shared_ptr<A>,boost::shared_ptr<B>,boost::shared_ptr<C> > base_variant;
template <class Visitor>
struct visit_shared_ptr_get: public boost::static_visitor<typename Visitor::result_type>
{
//for unary visitors
template <class FirstArg>
typename Visitor::result_type operator()(FirstArg& first) const
{
return Visitor()(first.get());
}
//for binary visitors, only the first argument is "ripped"
template <class FirstArg, class SecondArg>
typename Visitor::result_type operator()(FirstArg& first, SecondArg& second) const
{
return Visitor()(first.get(), second);
}
};
struct variant_visitor : public boost::static_visitor<void> {
void operator()(A*, base_ptr) const {std::cout << "A*\n";}
void operator()(B*, base_ptr) const {std::cout << "B*\n";}
void operator()(C*, base_ptr) const {std::cout << "C*\n";}
};
int main(int, char**)
{
// This works, of course.
base_ptr b(new A());
base_variant v(boost::shared_ptr<A>(new A()));
boost::apply_visitor(boost::bind(visit_shared_ptr_get<variant_visitor>(), _1, b), v);
return EXIT_SUCCESS;
}
Редактировать: downcaster, который вы, кажется, представляете.
#include <stdexcept>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/preprocessor/repetition.hpp>
//dynamic_cast will only compile if the target type is a pointer
template <class Derived, class Base, class Variant>
typename boost::enable_if<boost::is_pointer<Derived>, bool>::type cast_if_pointer( Base* b, Variant& variant)
{
if (Derived p = dynamic_cast<Derived>(b)) { variant = p; return true; }
return false;
}
//weeds out boost's unused template parameters and other non-pointers
template <class Derived, class Base, class Variant>
typename boost::disable_if<boost::is_pointer<Derived>, bool>::type cast_if_pointer( Base*, Variant& )
{
return false;
}
template <class P, BOOST_VARIANT_ENUM_PARAMS(class T)>
void rip(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant, const boost::shared_ptr<P>& smart_ptr)
{
#define ATTEMPT_CAST(z, n, type) if (cast_if_pointer<T ## n >(smart_ptr.get(), variant)) return;
BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES, ATTEMPT_CAST, T)
#undef ATTEMPT_CAST
throw std::bad_cast();
}
struct Base
{
virtual ~Base() {}
};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef boost::shared_ptr<Base> base_ptr;
typedef boost::variant<A*,B*,C*> base_variant;
int main(int, char**)
{
base_ptr b(new A());
base_variant v;
rip(v, b);
return EXIT_SUCCESS;
}