Re: extending interfaces with variadic templates...
On Friday, October 12, 2012 8:03:55 PM UTC+2, Werner wrote:
Hi All,
I want to try the following:
typedef CurveMetaDataIF<QPen,QBrush> BrushPenIF;
where the amount of elements in CurveMetaDataIF can be arbitrary.
BrushPenIF would be used as follows:
brushPenIF_->getData<QBrush>();
brushPenIF_->getData<QPen>();
...etc...
My first stab at the problem looked like this (used boost::mpl):
template <>
struct CurveMetaDataIF<>
{
virtual ~CurveMetaDataIF(){}
};
template <class Head, class... Tail>
struct CurveMetaDataIF<Head, Tail...> : CurveMetaDataIF<Tail...>
{
protected:
virtual Head getDataImpl( boost::identity<Head> ) const = 0;
public:
template <class DataT>
DataT getData()
{
return this->getDataImpl( boost::identity<DataT>() );
}
};
The problem with this approach is that getDataImpl of this
hides all bases.
I've come up with a nasty solution that finds the right base
(ugly), but was wondering whether anyone has some good
suggestion?
Help appreciated! Not homework...
Regards,
Werner
Thank you for your responses. Other solutions and critique
are always welcome.
I can't give this too much time. This was what I came up with for
now(for interest sake).
I will look into this in future and at loki (again).
#include <boost/mpl/identity.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_same.hpp>
struct CurveMetaDataIF_Base
{
//Common enumerator applicable to entire hierarchy.
enum{ eNotApplicable = -1 };
//We might be deleted via this interface...
virtual ~CurveMetaDataIF_Base(){ }
};
//Is as template expecting a list.
template <class... DataElem>
struct CurveMetaDataIF_Priv;
//Specialisation for tail.
template<class Tail>
struct CurveMetaDataIF_Priv<Tail> : CurveMetaDataIF_Base
{
protected:
virtual Tail getCurveData(
boost::mpl::identity<Tail>,
int seriesID = eNotApplicable ) const = 0;
template <class DataT>
struct FindType{ typedef CurveMetaDataIF_Priv<Tail> type; };
};
//Specialisation for list.
template <class Head, class... Tail>
struct CurveMetaDataIF_Priv<Head, Tail...> : CurveMetaDataIF_Priv<Tail...>
{
protected:
virtual Head getCurveData(
boost::mpl::identity<Head>,
int seriesID = CurveMetaDataIF_Base::eNotApplicable ) const = 0;
template <class DataT>
struct FindType
{
typedef typename CurveMetaDataIF_Priv<Tail...>::
template FindType<DataT>::type BaseFindOp;
typedef typename boost::mpl::if_<
boost::is_same<DataT,Head>,
CurveMetaDataIF_Priv<Head,Tail...>,
BaseFindOp>::type type;
};
};
//We want getData to apply to both specialisations.
template <class... Tail>
struct CurveMetaDataIF : CurveMetaDataIF_Priv<Tail...>
{
template <class DataT>
DataT getData( int seriesID = CurveMetaDataIF_Base::eNotApplicable ) const
{
//If DataT is Head, use Head.
//Else DataT lives somewhere in tail...
typedef typename CurveMetaDataIF_Priv<Tail...>::
template FindType<DataT>::type BaseT;
return BaseT::getCurveData(
boost::mpl::identity<DataT>(), seriesID );
}
};