Template specialisation of class with base class template ?!

Discussion in 'C++' started by Tim Clacy, Dec 3, 2003.

  1. Tim Clacy

    Tim Clacy Guest

    Your expertise will be appreciated...

    Here's a general templatised class; all specialisations of this class should
    have a pointer to a specialisation of the same, templatised type:

    template<typename T, const int N>
    struct Base : T
    {
    typedef Base<T, N> Type;

    Type* pNext;
    };


    However, what if I want a specialisation that has the base class Type and
    pNext members, but also a specific function:


    // Specialisation of Base, with an additional interface
    //
    template<>
    struct Base<SomeClass, 3>
    {
    void fn(void);
    };

    ....this doesn't have the general base class members Type and pNext.

    What's the correct thing to do here? If I specialise by derivation instead
    of template specialisation, then in addition to the template(s) we'll need
    derived types and to know what the derived type are called; I would really
    like to be able to just use the template with specialisations for 'special'
    flavours.

    As usual, I ready to hang my head in shame when someone points out a better
    approach


    Tim
     
    Tim Clacy, Dec 3, 2003
    #1
    1. Advertising

  2. "Tim Clacy" <> wrote...
    > Your expertise will be appreciated...
    >
    > Here's a general templatised class; all specialisations of this class

    should
    > have a pointer to a specialisation of the same, templatised type:
    >
    > template<typename T, const int N>
    > struct Base : T
    > {
    > typedef Base<T, N> Type;
    >
    > Type* pNext;
    > };
    >
    >
    > However, what if I want a specialisation that has the base class Type and
    > pNext members, but also a specific function:
    >
    >
    > // Specialisation of Base, with an additional interface
    > //
    > template<>
    > struct Base<SomeClass, 3>
    > {
    > void fn(void);
    > };
    >
    > ...this doesn't have the general base class members Type and pNext.
    >
    > What's the correct thing to do here?


    You have to declare pNext there. 'Type' you already specialised,
    it is 'SomeClass'. So, add

    SomeClass* pNext;

    where appropriate.

    > If I specialise by derivation instead
    > of template specialisation, then in addition to the template(s) we'll need
    > derived types and to know what the derived type are called; I would really
    > like to be able to just use the template with specialisations for

    'special'
    > flavours.


    You can do that if you split the parts of the template into what
    stays and what changes. See "Modern C++ Design" and policy-based
    programming.

    > As usual, I ready to hang my head in shame when someone points out a

    better
    > approach


    Templates do create an illusion of too much flexibility and too little
    programmer involvement, which is what it is, just an illusion. You still
    have to do many things yourself.

    Victor
     
    Victor Bazarov, Dec 3, 2003
    #2
    1. Advertising

  3. Tim Clacy

    Dan W. Guest

    On Wed, 3 Dec 2003 13:07:54 +0100, "Tim Clacy"
    <> wrote:

    >Your expertise will be appreciated...
    >
    >Here's a general templatised class; all specialisations of this class should
    >have a pointer to a specialisation of the same, templatised type:
    >
    >template<typename T, const int N>
    >struct Base : T
    >{
    > typedef Base<T, N> Type;
    >
    > Type* pNext;
    >};
    >
    >
    >However, what if I want a specialisation that has the base class Type and
    >pNext members, but also a specific function:
    >
    >
    >// Specialisation of Base, with an additional interface
    >//
    >template<>
    >struct Base<SomeClass, 3>
    >{
    > void fn(void);
    >};
    >
    >...this doesn't have the general base class members Type and pNext.
    >
    >What's the correct thing to do here? If I specialise by derivation instead
    >of template specialisation, then in addition to the template(s) we'll need
    >derived types and to know what the derived type are called; I would really
    >like to be able to just use the template with specialisations for 'special'
    >flavours.
    >
    >As usual, I ready to hang my head in shame when someone points out a better
    >approach
    >
    >
    >Tim
    >


    Would this work for you?

    template<typename T, const int N>
    struct Base : T
    {
    typedef Base<T, N> Type;
    Type* pNext;
    };

    template< typename T, const int N >
    struct Derived : Base<T, N>
    {
    typedef Derived<T, N> Type;
    };

    template<>
    struct Derived<SomeClass, 3>
    {
    void fn(void);
    };

    Hmmm, really not sure whether my specialization syntax is okay...
     
    Dan W., Dec 3, 2003
    #3
  4. Tim Clacy

    Tim Clacy Guest

    Victor Bazarov wrote:

    <snip>
    >> What's the correct thing to do here?

    >
    > You have to declare pNext there. 'Type' you already specialised,
    > it is 'SomeClass'. So, add
    >
    > SomeClass* pNext;
    >
    > where appropriate.


    Victor,

    Hi. I don't want a pointer to some class; I want a pointer to
    Base<SomeClass, 3>. In other words, evey template specialisation of Base
    should have a pointer to another instance of its own, very specific type:

    template<typename T, const int N>
    struct Base
    {
    Base<T, N>* pNext;
    };

    If I make an explicit specialisation, then I seem to lose the 'Base'
    template defined 'pNext'.

    To paraphrase; is there a way to ADD functionality by template
    specialisation without LOOSING functionality defined in the base template?


    Best regards


    Tim
     
    Tim Clacy, Dec 3, 2003
    #4
  5. Tim Clacy

    Tim Clacy Guest

    Dan W. wrote:
    > On Wed, 3 Dec 2003 13:07:54 +0100, "Tim Clacy"
    > <> wrote:
    >
    >> Your expertise will be appreciated...
    >>
    >> Here's a general templatised class; all specialisations of this
    >> class should have a pointer to a specialisation of the same,
    >> templatised type:
    >>
    >> template<typename T, const int N>
    >> struct Base : T
    >> {
    >> typedef Base<T, N> Type;
    >>
    >> Type* pNext;
    >> };
    >>
    >>
    >> However, what if I want a specialisation that has the base class
    >> Type and pNext members, but also a specific function:
    >>
    >>
    >> // Specialisation of Base, with an additional interface
    >> //
    >> template<>
    >> struct Base<SomeClass, 3>
    >> {
    >> void fn(void);
    >> };
    >>
    >> ...this doesn't have the general base class members Type and pNext.
    >>
    >> What's the correct thing to do here? If I specialise by derivation
    >> instead of template specialisation, then in addition to the
    >> template(s) we'll need derived types and to know what the derived
    >> type are called; I would really like to be able to just use the
    >> template with specialisations for 'special' flavours.
    >>
    >> As usual, I ready to hang my head in shame when someone points out a
    >> better approach
    >>
    >>
    >> Tim
    >>

    >
    > Would this work for you?
    >
    > template<typename T, const int N>
    > struct Base : T
    > {
    > typedef Base<T, N> Type;
    > Type* pNext;
    > };
    >
    > template< typename T, const int N >
    > struct Derived : Base<T, N>
    > {
    > typedef Derived<T, N> Type;
    > };
    >
    > template<>
    > struct Derived<SomeClass, 3>
    > {
    > void fn(void);
    > };
    >
    > Hmmm, really not sure whether my specialization syntax is okay...


    Dan,

    Hi. That looks about right... except that Derived::fn() can't be called
    through pNext (since pNext is a layer lower in the ancestry). I'm trying to
    implement something similar to a protocol stack using specialisations of a
    base 'Port' structure; each layer should be able to communicate to the equal
    layer at the other end of the link by passing data down the port ancestry
    one end and up the port ancestry at the other end.
     
    Tim Clacy, Dec 3, 2003
    #5
  6. Tim Clacy

    Dan W. Guest

    On Wed, 3 Dec 2003 16:12:29 +0100, "Tim Clacy"
    <> wrote:

    >Victor Bazarov wrote:
    >
    ><snip>
    >>> What's the correct thing to do here?

    >>
    >> You have to declare pNext there. 'Type' you already specialised,
    >> it is 'SomeClass'. So, add
    >>
    >> SomeClass* pNext;
    >>
    >> where appropriate.

    >
    >Victor,
    >
    >Hi. I don't want a pointer to some class; I want a pointer to
    >Base<SomeClass, 3>. In other words, evey template specialisation of Base
    >should have a pointer to another instance of its own, very specific type:
    >
    >template<typename T, const int N>
    >struct Base
    >{
    > Base<T, N>* pNext;
    >};
    >
    >If I make an explicit specialisation, then I seem to lose the 'Base'
    >template defined 'pNext'.
    >
    >To paraphrase; is there a way to ADD functionality by template
    >specialisation without LOOSING functionality defined in the base template?
    >
    >
    >Best regards
    >
    >
    >Tim
    >


    Would this work?:

    template < typename U >
    struct Base
    {
    U *pDerived;
    };

    template < typename T, const int X >
    struct Derived : Base < Derived< T, X > >
    {
    };

    template <>
    struct Derived < someclass, 3 >
    {
    void f();
    }:
     
    Dan W., Dec 3, 2003
    #6
  7. Tim Clacy

    Dan W. Guest

    >> Would this work for you?
    >>
    >> template<typename T, const int N>
    >> struct Base : T
    >> {
    >> typedef Base<T, N> Type;
    >> Type* pNext;
    >> };
    >>
    >> template< typename T, const int N >
    >> struct Derived : Base<T, N>
    >> {
    >> typedef Derived<T, N> Type;
    >> };
    >>
    >> template<>
    >> struct Derived<SomeClass, 3>
    >> {
    >> void fn(void);
    >> };
    >>
    >> Hmmm, really not sure whether my specialization syntax is okay...

    >
    >Dan,
    >
    >Hi. That looks about right... except that Derived::fn() can't be called
    >through pNext (since pNext is a layer lower in the ancestry). I'm trying to
    >implement something similar to a protocol stack using specialisations of a
    >base 'Port' structure; each layer should be able to communicate to the equal
    >layer at the other end of the link by passing data down the port ancestry
    >one end and up the port ancestry at the other end.
    >


    Ok, so this is what you want, then:


    template < typename U >
    struct Base
    {
    U *pDerived;
    };

    template < typename T, const int X >
    struct Derived : Base < Derived< T, X > >
    {
    };

    template <>
    struct Derived < someclass, 3 >
    {
    void fn();
    }:
     
    Dan W., Dec 3, 2003
    #7
  8. Tim Clacy

    Tim Clacy Guest

    Dan W. wrote:
    >>> Would this work for you?
    >>>
    >>> template<typename T, const int N>
    >>> struct Base : T
    >>> {
    >>> typedef Base<T, N> Type;
    >>> Type* pNext;
    >>> };
    >>>
    >>> template< typename T, const int N >
    >>> struct Derived : Base<T, N>
    >>> {
    >>> typedef Derived<T, N> Type;
    >>> };
    >>>
    >>> template<>
    >>> struct Derived<SomeClass, 3>
    >>> {
    >>> void fn(void);
    >>> };
    >>>
    >>> Hmmm, really not sure whether my specialization syntax is okay...

    >>
    >> Dan,
    >>
    >> Hi. That looks about right... except that Derived::fn() can't be
    >> called through pNext (since pNext is a layer lower in the ancestry).
    >> I'm trying to implement something similar to a protocol stack using
    >> specialisations of a base 'Port' structure; each layer should be
    >> able to communicate to the equal layer at the other end of the link
    >> by passing data down the port ancestry one end and up the port
    >> ancestry at the other end.
    >>

    >
    > Ok, so this is what you want, then:
    >
    >
    > template < typename U >
    > struct Base
    > {
    > U *pDerived;
    > };
    >
    > template < typename T, const int X >
    > struct Derived : Base < Derived< T, X > >
    > {
    > };
    >
    > template <>
    > struct Derived < someclass, 3 >
    > {
    > void fn();
    > }:


    Spot on... probably

    It seems to compile too. I can't quite see how it expands out though (I get
    a head-ache exception trying to expand the templates). Can you explain how
    Derived can have a Base that is defined in terms of an expansion of Derived?
    Isn't there some kind of recursive definition there? What is the actual base
    class of 1) Derived<T, X> and 2) Derived<someclass, 3>?

    Many thanks


    Tim
     
    Tim Clacy, Dec 3, 2003
    #8
  9. Tim Clacy

    Dan W. Guest

    >> Ok, so this is what you want, then:
    >>
    >>
    >> template < typename U >
    >> struct Base
    >> {
    >> U *pDerived;
    >> };
    >>
    >> template < typename T, const int X >
    >> struct Derived : Base < Derived< T, X > >
    >> {
    >> };
    >>
    >> template <>
    >> struct Derived < someclass, 3 >
    >> {
    >> void fn();
    >> }:

    >
    >Spot on... probably
    >
    >It seems to compile too. I can't quite see how it expands out though (I get
    >a head-ache exception trying to expand the templates). Can you explain how
    >Derived can have a Base that is defined in terms of an expansion of Derived?
    >Isn't there some kind of recursive definition there? What is the actual base
    >class of 1) Derived<T, X> and 2) Derived<someclass, 3>?
    >
    >Many thanks
    >
    >
    >Tim
    >


    If you like headaches, look at boost's mpl library... ;-)

    There would be an un-solvable recursion if you tried,

    template < typename X >
    struct t_x
    {
    X an_x;
    };

    template < typename T, typename U
    struct t_tu : t_x < t_tu< T, U >
    {
    };

    because the compiler would need to know the size of each before it can
    compute the size of the other. (Size is everything to a compiler :)
    But if all that the template parameter for the base does is define the
    type of a pointer in it, or anything that doesn't affect the class'
    size, it can build it, and so it can inherit it. Template instances of
    it are only compiled when needed, which in our case it's when the
    derived template is compiled.

    1) The type of the base class is

    Base< Derived< T, X > >

    2) You got it

    Cheers!
     
    Dan W., Dec 3, 2003
    #9
  10. Tim Clacy

    tom_usenet Guest

    On Wed, 3 Dec 2003 17:28:46 +0100, "Tim Clacy"
    <> wrote:

    >> Ok, so this is what you want, then:
    >>
    >>
    >> template < typename U >
    >> struct Base
    >> {
    >> U *pDerived;
    >> };
    >>
    >> template < typename T, const int X >
    >> struct Derived : Base < Derived< T, X > >
    >> {
    >> };
    >>
    >> template <>
    >> struct Derived < someclass, 3 >
    >> {
    >> void fn();
    >> }:

    >
    >Spot on... probably
    >
    >It seems to compile too. I can't quite see how it expands out though (I get
    >a head-ache exception trying to expand the templates). Can you explain how
    >Derived can have a Base that is defined in terms of an expansion of Derived?


    It's called the "Curiously recurring template pattern" - google it.

    >Isn't there some kind of recursive definition there?


    Yes, derived<T> is defined in terms of derived<T>! This is fine since
    Base doesn't require U to be a complete type (it is only declaring a
    pointer member).

    What is the actual base
    >class of 1) Derived<T, X> and 2) Derived<someclass, 3>?


    1) Base<Derived<T,X> >
    2) Base<Derived<someclass, 3> >

    Tom

    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
     
    tom_usenet, Dec 3, 2003
    #10
  11. Tim Clacy

    Tim Clacy Guest

    Dan W. wrote:
    >>> Ok, so this is what you want, then:
    >>>
    >>>
    >>> template < typename U >
    >>> struct Base
    >>> {
    >>> U *pDerived;
    >>> };
    >>>
    >>> template < typename T, const int X >
    >>> struct Derived : Base < Derived< T, X > >
    >>> {
    >>> };
    >>>
    >>> template <>
    >>> struct Derived < someclass, 3 >
    >>> {
    >>> void fn();
    >>> }:

    >>
    >> Spot on... probably
    >>
    >> It seems to compile too. I can't quite see how it expands out though
    >> (I get a head-ache exception trying to expand the templates). Can
    >> you explain how Derived can have a Base that is defined in terms of
    >> an expansion of Derived? Isn't there some kind of recursive
    >> definition there? What is the actual base class of 1) Derived<T, X>
    >> and 2) Derived<someclass, 3>?
    >>
    >> Many thanks
    >>
    >>
    >> Tim
    >>

    >
    > If you like headaches, look at boost's mpl library... ;-)
    >
    > There would be an un-solvable recursion if you tried,
    >
    > template < typename X >
    > struct t_x
    > {
    > X an_x;
    > };
    >
    > template < typename T, typename U
    > struct t_tu : t_x < t_tu< T, U >
    > {
    > };
    >
    > because the compiler would need to know the size of each before it can
    > compute the size of the other. (Size is everything to a compiler :)
    > But if all that the template parameter for the base does is define the
    > type of a pointer in it, or anything that doesn't affect the class'
    > size, it can build it, and so it can inherit it. Template instances of
    > it are only compiled when needed, which in our case it's when the
    > derived template is compiled.
    >
    > 1) The type of the base class is
    >
    > Base< Derived< T, X > >
    >
    > 2) You got it
    >
    > Cheers!


    Thanks Dan
     
    Tim Clacy, Dec 3, 2003
    #11
  12. Tim Clacy

    Tim Clacy Guest

    tom_usenet wrote:
    > On Wed, 3 Dec 2003 17:28:46 +0100, "Tim Clacy"
    > <> wrote:
    >
    >>> Ok, so this is what you want, then:
    >>>
    >>>
    >>> template < typename U >
    >>> struct Base
    >>> {
    >>> U *pDerived;
    >>> };
    >>>
    >>> template < typename T, const int X >
    >>> struct Derived : Base < Derived< T, X > >
    >>> {
    >>> };
    >>>
    >>> template <>
    >>> struct Derived < someclass, 3 >
    >>> {
    >>> void fn();
    >>> }:

    >>
    >> Spot on... probably
    >>
    >> It seems to compile too. I can't quite see how it expands out though
    >> (I get a head-ache exception trying to expand the templates). Can
    >> you explain how Derived can have a Base that is defined in terms of
    >> an expansion of Derived?

    >
    > It's called the "Curiously recurring template pattern" - google it.
    >
    >> Isn't there some kind of recursive definition there?

    >
    > Yes, derived<T> is defined in terms of derived<T>! This is fine since
    > Base doesn't require U to be a complete type (it is only declaring a
    > pointer member).
    >
    > What is the actual base
    >> class of 1) Derived<T, X> and 2) Derived<someclass, 3>?

    >
    > 1) Base<Derived<T,X> >
    > 2) Base<Derived<someclass, 3> >
    >
    > Tom
    >
    > C++ FAQ: http://www.parashift.com/c -faq-lite/
    > C FAQ: http://www.eskimo.com/~scs/C-faq/top.html


    Thanks Tom; I will pursue this "Curiously recurring template pattern" until
    I understand it.
     
    Tim Clacy, Dec 3, 2003
    #12
  13. Tim Clacy

    Dan W. Guest

    Think of it this way: The base class exists outside the derived class
    only in concept; but it lives inside the derived class, when the
    latter is instantiated; and they are compiled together in one shot.

    Cheers!
     
    Dan W., Dec 3, 2003
    #13
    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. Ben
    Replies:
    1
    Views:
    329
    Victor Bazarov
    Aug 12, 2003
  2. Nicolas Weidmann
    Replies:
    1
    Views:
    311
    Christian Jaeger
    Feb 17, 2004
  3. Lionel B
    Replies:
    7
    Views:
    1,431
    Lionel B
    Nov 4, 2004
  4. Adrian Hawryluk

    Template class partial specialisation

    Adrian Hawryluk, Mar 19, 2007, in forum: C++
    Replies:
    2
    Views:
    329
    Adrian Hawryluk
    Mar 19, 2007
  5. Hicham Mouline
    Replies:
    1
    Views:
    596
    Victor Bazarov
    Apr 20, 2009
Loading...

Share This Page