Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   extending interfaces with variadic templates... (http://www.velocityreviews.com/forums/t953304-extending-interfaces-with-variadic-templates.html)

Werner 10-12-2012 06:03 PM

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



Luca Risolia 10-13-2012 03:18 PM

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;
}


Pavel 10-15-2012 02:28 AM

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



Werner 10-15-2012 07:28 AM

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 );
}
};

Werner 10-15-2012 05:19 PM

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.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57