Template specialisation of class with base class template ?!

T

Tim Clacy

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
 
V

Victor Bazarov

Tim Clacy said:
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
 
D

Dan W.

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...
 
T

Tim Clacy

Victor Bazarov wrote:

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
 
T

Tim Clacy

Dan said:
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.
 
D

Dan W.

Victor Bazarov wrote:



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();
}:
 
D

Dan W.

Would this work for you?
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();
}:
 
T

Tim Clacy

Dan said:
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
 
D

Dan W.

Ok, so this is what you want, then:
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!
 
T

tom_usenet

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
 
T

Tim Clacy

Dan said:
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
 
T

Tim Clacy

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


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

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.
 
D

Dan W.

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!
 

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,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top