
It looks like we are heading for an alternative approach (again). Based on the boost::variant i'm writing my own variant that is optimized to only hold shared_ptr's. First test seem promising i can finally create variants with 200 types in 2 sec compilation :) However binary invokation is even here quickly a problem, its generating 'paths' quadratically, 50 bounded types produce 2500 paths.... Maybe anyone can provide some feedback on following implementation? Thanks, Paul template<typename Typelist> class CLoPtrVariant { public: CLoPtrVariant() : m_uiSelect(0) { // precondition assertions BOOST_STATIC_ASSERT((boost::mpl::is_sequence<Typelist>::value)); } template<typename Type> CLoPtrVariant(const boost::shared_ptr<Type>& rspValue) { assign(rspValue); } CLoPtrVariant(const CLoPtrVariant& rOperand) { m_spSelect = rOperand.m_spSelect; m_uiSelect = rOperand.m_uiSelect; } template<typename Typelist2> CLoPtrVariant(const CLoPtrVariant<Typelist2>& rOperand) { CConvertVariant<Typelist> convert(*this); apply_visitor(convert, rOperand); } template<typename Type> CLoPtrVariant& operator=(const boost::shared_ptr<Type>& rspValue) { assign(rspValue); return *this; } template<typename Type> CLoPtrVariant& operator=(boost::shared_ptr<Type>& rspValue) { assign(rspValue); return *this; } bool operator<(const CLoPtrVariant& rRhs) const { if(m_uiSelect != rRhs.m_uiSelect) { return (m_uiSelect < rRhs.m_uiSelect); } else { return (m_spSelect < rRhs.m_spSelect); } } bool operator==(const CLoPtrVariant& rRhs) const { return (m_uiSelect == rRhs.m_uiSelect && m_spSelect == rRhs.m_spSelect); } bool operator!=(const CLoPtrVariant& rRhs) const { return !(*this == rRhs); } template<typename VisitorType> typename VisitorType::result_type apply_visitor(VisitorType& rVisitor) const { switch (m_uiSelect) { #ifdef BOOST_PP_LOCAL_ITERATE #define BOOST_PP_LOCAL_MACRO(n) \ case n: \ return apply_visitor_impl<VisitorType, boost::mpl::int_<n>
(rVisitor); \ break; #define BOOST_PP_LOCAL_LIMITS (0, 100) //Notice increasing this number slows down compilation times, espacially binary visitation decreases quadratic #include BOOST_PP_LOCAL_ITERATE() default: BOOST_ASSERT(m_uiSelect); //Out of bounds; CLoPtrVariant is missing code to access the sequence at given index, increase the upperlimit in BOOST_PP_LOCAL_LIMITS return VisitorType::result_type(); #endif //BOOST_PP_LOCAL_ITERATE } }
size_t GetWhich() const { return m_uiSelect; } void SetWhich(size_t which) { LO_CHECK(!m_spSelect); m_uiSelect = which; } private: template<typename Type> void assign(const boost::shared_ptr<Type>& rspValue) { typedef boost::mpl::find<Typelist, boost::shared_ptr<Type>
::type pos_t; typedef boost::mpl::end<Typelist>::type end_t; BOOST_STATIC_ASSERT((!boost::is_same<pos_t, end_t>::value)); m_spSelect = boost::static_pointer_cast<void>(rspValue); m_uiSelect = pos_t::pos::value; }
template<typename VisitorType, typename IndexType> inline typename VisitorType::result_type apply_visitor_impl(VisitorType& rVisitor, boost::mpl::true_ /*is_unrolled_t*/) const { typedef boost::mpl::at<Typelist, IndexType>::type type_t; return rVisitor(boost::static_pointer_cast<type_t::value_type>(m_spSelect)); } template<typename VisitorType, typename IndexType> inline typename VisitorType::result_type apply_visitor_impl(VisitorType& rVisitor, boost::mpl::false_ /*is_unrolled_t*/) const { //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds BOOST_ASSERT(false); return VisitorType::result_type(); } template<typename VisitorType, typename IndexType> inline typename VisitorType::result_type apply_visitor_impl(VisitorType& rVisitor) const { typedef typename boost::mpl::less<IndexType, boost::mpl::size<Typelist>::type>::type is_unrolled_t; return apply_visitor_impl<VisitorType, IndexType>(rVisitor, is_unrolled_t()); } private: boost::shared_ptr<void> m_spSelect; size_t m_uiSelect; }; //Helper function-template to construct the variant type template<typename Typelist> struct make_variant_over { public: typedef CLoPtrVariant<Typelist> type; }; //Unary visitation template<typename Visitor, typename Visitable> inline typename Visitor::result_type apply_visitor(const Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor(visitor); } template<typename Visitor, typename Visitable> inline typename Visitor::result_type apply_visitor(Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor(visitor); } //Binary visitation template <typename Visitor, typename Visitable2> class CBinaryUnwrap1 { public: typedef typename Visitor::result_type result_type; private: Visitor& visitor_; Visitable2& visitable2_; public: CBinaryUnwrap1(Visitor& visitor, Visitable2& visitable2) : visitor_(visitor) , visitable2_(visitable2) { } public: template<typename Value1> result_type operator()(Value1& value1) { CBinaryUnwrap2<Visitor, Value1> unwrapper(visitor_, value1); return apply_visitor(unwrapper, visitable2_); } }; template<typename Visitor, typename Value1> class CBinaryUnwrap2 { public: typedef typename Visitor::result_type result_type; private: Visitor& visitor_; Value1& value1_; public: CBinaryUnwrap2(Visitor& visitor, Value1& value1) : visitor_(visitor) , value1_(value1) { } public: template <typename Value2> result_type operator()(Value2& value2) { return visitor_(value1_, value2); } }; template<typename Visitor, typename Visitable1, typename Visitable2> inline typename Visitor::result_type apply_visitor(const Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2) { CBinaryUnwrap1<const Visitor, Visitable2> unwrapper(visitor, visitable2); return apply_visitor(unwrapper, visitable1); } template<typename Visitor, typename Visitable1, typename Visitable2> inline typename Visitor::result_type apply_visitor(Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2) { CBinaryUnwrap1<Visitor, Visitable2> unwrapper(visitor, visitable2); return apply_visitor(unwrapper, visitable1); } //Base class for visitor classes template<typename R = void> class static_visitor { public: typedef R result_type; protected: // for use as base class only static_visitor() { } ~static_visitor() { } }; template<typename Base, typename Derived> struct is_base_of_smartptr : boost::is_base_of<typename Base::value_type, typename Derived::value_type> { }; //Convert variant types template<typename Typelist> class CConvertVariant : public static_visitor<> { public: CConvertVariant(CLoPtrVariant<Typelist>& rVariant) : m_rVariant(rVariant) { } template<typename Pos, typename Type> void assign_variant(boost::shared_ptr<Type>& rValue, boost::mpl::false_) //convertible { typedef boost::mpl::deref<Pos>::type type_t; m_rVariant = boost::static_pointer_cast<type_t::value_type>(rValue); } template<typename Pos, typename Type> void assign_variant(boost::shared_ptr<Type>& rValue, boost::mpl::true_) //not convertible { BOOST_STATIC_ASSERT((boost::mpl::false_)); //Compiler error here indicates that (one of) the variants bounded types is not convertible to the target variant type m_rVariant = rValue; } template<typename T> void operator()(boost::shared_ptr<T>& rValue) //T is not const to match the variant bounded types { typedef boost::mpl::find_if<Typelist, is_base_of_smartptr<boost::mpl::_1, boost::shared_ptr<T> > >::type pos_t; typedef boost::mpl::end<Typelist>::type end_t; typedef boost::is_same<pos_t, end_t>::type not_convertible; assign_variant<pos_t>(rValue, not_convertible()); } private: CLoPtrVariant<Typelist>& m_rVariant; }; //Delayed visitation (std algorithm support) template<typename VisitorType> class CVisitDelayed { public: typedef typename VisitorType::result_type result_type; private: VisitorType& visitor_; public: explicit CVisitDelayed(VisitorType& visitor) : visitor_(visitor) { } public: //Unary template<typename Visitable> result_type operator()(Visitable& visitable) { return apply_visitor(visitor_, visitable); } //Binary template<typename Visitable1, typename Visitable2> result_type operator()(Visitable1& visitable1, Visitable2& visitable2) { return apply_visitor(visitor_, visitable1, visitable2); } }; template<typename VisitorType> inline CVisitDelayed<VisitorType> apply_visitor(VisitorType& visitor) { return CVisitDelayed<VisitorType>(visitor); }