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
(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
::type pos_t;
typedef boost::mpl::end<Typelist>::type end_t;
BOOST_STATIC_ASSERT((!boost::is_same::value));
m_spSelect = boost::static_pointer_cast<void>(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();
}
template
inline typename VisitorType::result_type
apply_visitor_impl(VisitorType& rVisitor) const
{
typedef typename boost::mpl::less::type is_unrolled_t;
return apply_visitor_impl(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
inline typename Visitor::result_type apply_visitor(const Visitor&
visitor, Visitable& visitable)
{
return visitable.apply_visitor(visitor);
}
template
inline typename Visitor::result_type apply_visitor(Visitor& visitor,
Visitable& visitable)
{
return visitable.apply_visitor(visitor);
}
//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<typename Value1>
result_type operator()(Value1& value1)
{
CBinaryUnwrap2 unwrapper(visitor_, value1);
return 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 <typename Value2>
result_type operator()(Value2& value2)
{
return visitor_(value1_, value2);
}
};
template
inline typename Visitor::result_type apply_visitor(const Visitor&
visitor, Visitable1& visitable1, Visitable2& visitable2)
{
CBinaryUnwrap1 unwrapper(visitor,
visitable2);
return apply_visitor(unwrapper, visitable1);
}
template
inline typename Visitor::result_type apply_visitor(Visitor& visitor,
Visitable1& visitable1, Visitable2& visitable2)
{
CBinaryUnwrap1 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
struct is_base_of_smartptr
: boost::is_base_of
{
};
//Convert variant types
template<typename Typelist>
class CConvertVariant
: public static_visitor<>
{
public:
CConvertVariant(CLoPtrVariant<Typelist>& rVariant)
: m_rVariant(rVariant)
{
}
template
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(rValue);
}
template
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 >::type pos_t;
typedef boost::mpl::end<Typelist>::type end_t;
typedef boost::is_same::type not_convertible;
assign_variant(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
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);
}