extending interfaces with variadic templates...

Discussion in 'C++' started by Werner, Oct 12, 2012.

  1. Werner

    Werner Guest

    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
     
    Werner, Oct 12, 2012
    #1
    1. Advertising

  2. Werner

    Luca Risolia Guest

    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;
    }
     
    Luca Risolia, Oct 13, 2012
    #2
    1. Advertising

  3. Werner

    Pavel Guest

    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-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
     
    Pavel, Oct 15, 2012
    #3
  4. Werner

    Werner Guest

    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, Oct 15, 2012
    #4
  5. Werner

    Werner Guest

    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
     
    Werner, Oct 15, 2012
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Colin Walters
    Replies:
    2
    Views:
    535
    Ben Pfaff
    Feb 13, 2004
  2. Ross A. Finlayson
    Replies:
    19
    Views:
    624
    Keith Thompson
    Mar 10, 2005
  3. Replies:
    2
    Views:
    361
    Dave Thompson
    Feb 27, 2006
  4. Replies:
    5
    Views:
    375
  5. Valeriu Catina

    c++0x variadic templates

    Valeriu Catina, Mar 13, 2008, in forum: C++
    Replies:
    3
    Views:
    620
    Erik Wikström
    Mar 13, 2008
Loading...

Share This Page