![]() |
extending interfaces with variadic templates...
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 |
Re: extending interfaces with variadic templates...
On 12/10/2012 20:03, 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>(); Is this what you want? template<class... T> struct CurveMetaDataIF : public T... { template <class DataT> DataT getData() { return static_cast<DataT*>(this)->getDataImpl(); } }; struct QPen { QPen getDataImpl() const { /* do something; */ return *this; } }; struct QBrush { QBrush getDataImpl() const { /* do something; */ return *this; } }; typedef CurveMetaDataIF<QPen, QBrush> BrushPenIF; int main() { BrushPenIF brushPenIF_; brushPenIF_.getData<QBrush>(); brushPenIF_.getData<QPen>(); return 0; } |
Re: extending interfaces with variadic templates...
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 > > If you are ok with a slightly different but seemingly equivalent acces interface you can take advantage of Andrew Alexanderscu's loki (http://sourceforge.net/projects/loki...r.bz2/download). Look for the the Field function specializations in HierarchyGenerators.h there. NOTE: Usually people end up using tuples accessing values by index rather than type, to be able to distinguish among several elements of the same type in their object (the requirement that might come late in the game, e.g. you will want the second pen or brush or color to draw your curves). The tuples with such access are more or less standardized, e.g. both boost and C++11 Standard Library have them. HTH -Pavel |
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 ); } }; |
Re: extending interfaces with variadic templates...
On Monday, October 15, 2012 9:28:53 AM UTC+2, Werner wrote:
> 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 ); > > } Sorry, slight mod to the code: 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 static_cast<const BaseT*>(this)->getCurveData( boost::mpl::identity<DataT>(), seriesID ); } .... We calling getCurveData polymorphically, hence not using BaseT:: but static_cast<const BaseT*>(this), and for this reason functions getCurveData also needs to be public. Werner |
| All times are GMT. The time now is 12:13 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.