namespace Layout { template class CLoPtrVariant { public: CLoPtrVariant() : m_uiSelect(0) { // precondition assertions BOOST_STATIC_ASSERT((boost::mpl::is_sequence::value)); } template CLoPtrVariant(const boost::shared_ptr& rspValue) { assign(rspValue); } CLoPtrVariant(const CLoPtrVariant& rOperand) { m_spSelect = rOperand.m_spSelect; m_uiSelect = rOperand.m_uiSelect; } template CLoPtrVariant(const CLoPtrVariant& rOperand) { CConvertVariant convert(*this); Layout::apply_visitor(convert, rOperand); } template CLoPtrVariant& operator=(const boost::shared_ptr& rspValue) { assign(rspValue); return *this; } template CLoPtrVariant& operator=(boost::shared_ptr& 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::result_type apply_visitor(VisitorType& rVisitor, boost::mpl::false_ /*unrolled*/) const { BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist return VisitorType::result_type(); } template typename VisitorType::result_type apply_visitor(VisitorType& rVisitor, boost::mpl::true_ /*unrolled*/) const { switch (m_uiSelect) { #ifdef BOOST_PP_LOCAL_ITERATE #define BOOST_PP_LOCAL_MACRO(n) \ case (WhichType::value + n): \ return apply_visitor_impl >(rVisitor, boost::mpl::less, boost::mpl::size::type>::type()); \ break; #define BOOST_PP_LOCAL_LIMITS (0, 10) #include BOOST_PP_LOCAL_ITERATE() #endif //BOOST_PP_LOCAL_ITERATE default: typedef boost::mpl::int_ next_which_t; return apply_visitor(rVisitor, boost::mpl::less::type>::type()); } } size_t GetWhich() const { return m_uiSelect; } void SetWhich(size_t which) { BOOST_ASSERT(!m_spSelect); m_uiSelect = which; } private: template void assign(const boost::shared_ptr& rspValue) { typedef boost::mpl::find >::type pos_t; typedef boost::mpl::end::type end_t; BOOST_STATIC_ASSERT((!boost::is_same::value)); m_spSelect = boost::static_pointer_cast(rspValue); m_uiSelect = pos_t::pos::value; } template inline typename VisitorType::result_type apply_visitor_impl(VisitorType& rVisitor, boost::mpl::true_ /*is_unrolled_t*/) const { typedef boost::mpl::at::type type_t; return rVisitor(boost::static_pointer_cast(m_spSelect)); } template 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(); } private: boost::shared_ptr m_spSelect; size_t m_uiSelect; }; //Helper function-template to construct the variant type template struct make_variant_over { public: typedef CLoPtrVariant type; }; //Unary visitation template inline typename Visitor::result_type apply_visitor(const Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor >(visitor, boost::mpl::true_()); } template inline typename Visitor::result_type apply_visitor(Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor >(visitor, boost::mpl::true_()); } //Binary visitation template 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 result_type operator()(Value1& value1) { CBinaryUnwrap2 unwrapper(visitor_, value1); return Layout::apply_visitor(unwrapper, visitable2_); } }; template 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 result_type operator()(Value2& value2) { return visitor_(value1_, value2); } }; template inline typename Visitor::result_type apply_visitor(const Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2) { //in 3 stappen doen; eerst visitable1 en visitable2 meegeven en daarna visit op visitable2 doen en resultaat v/d eerste meegeven, dan visit op de laatste Layout::CBinaryUnwrap1 unwrapper(visitor, visitable2); return Layout::apply_visitor(unwrapper, visitable1); } template inline typename Visitor::result_type apply_visitor(Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2) { Layout::CBinaryUnwrap1 unwrapper(visitor, visitable2); return Layout::apply_visitor(unwrapper, visitable1); } //Base class for visitor classes template class static_visitor { public: typedef R result_type; protected: // for use as base class only static_visitor() { } ~static_visitor() { } }; template struct is_base_of_smartptr : boost::is_base_of { }; //Convert variant types template class CConvertVariant : public static_visitor<> { public: CConvertVariant(CLoPtrVariant& rVariant) : m_rVariant(rVariant) { } template void assign_variant(boost::shared_ptr& rValue, boost::mpl::false_) //convertible { typedef boost::mpl::deref::type type_t; m_rVariant = boost::static_pointer_cast(rValue); } template void assign_variant(boost::shared_ptr& 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 void operator()(boost::shared_ptr& rValue) //T is not const to match the variant bounded types { typedef boost::mpl::find_if > >::type pos_t; typedef boost::mpl::end::type end_t; typedef boost::is_same::type not_convertible; assign_variant(rValue, not_convertible()); } private: CLoPtrVariant& m_rVariant; }; //Delayed visitation (std algorithm support) template class CVisitDelayed { public: typedef typename VisitorType::result_type result_type; private: VisitorType& visitor_; public: explicit CVisitDelayed(VisitorType& visitor) : visitor_(visitor) { } public: //Unary template result_type operator()(Visitable& visitable) { return Layout::apply_visitor(visitor_, visitable); } //Binary template result_type operator()(Visitable1& visitable1, Visitable2& visitable2) { return Layout::apply_visitor(visitor_, visitable1, visitable2); } }; template inline CVisitDelayed apply_visitor(VisitorType& visitor) { return CVisitDelayed(visitor); } }