extending interfaces with variadic templates...

W

Werner

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
 
L

Luca Risolia

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

Pavel

Werner said:
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-lib/files/Loki/Loki 0.1.7/loki-0.1.7.tar.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
 
W

Werner

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

Werner

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top