By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,897 Members | 1,955 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,897 IT Pros & Developers. It's quick & easy.

Template specialisation of class with base class template ?!

P: n/a
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
Jul 22 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
"Tim Clacy" <no*******@nospamphaseone.nospamdk> 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
Jul 22 '05 #2

P: n/a
On Wed, 3 Dec 2003 13:07:54 +0100, "Tim Clacy"
<no*******@nospamphaseone.nospamdk> 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...
Jul 22 '05 #3

P: n/a
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
Jul 22 '05 #4

P: n/a
Dan W. wrote:
On Wed, 3 Dec 2003 13:07:54 +0100, "Tim Clacy"
<no*******@nospamphaseone.nospamdk> 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.
Jul 22 '05 #5

P: n/a
On Wed, 3 Dec 2003 16:12:29 +0100, "Tim Clacy"
<no*******@nospamphaseone.nospamdk> 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();
}:

Jul 22 '05 #6

P: n/a
>> 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();
}:
Jul 22 '05 #7

P: n/a
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
Jul 22 '05 #8

P: n/a
>> 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!
Jul 22 '05 #9

P: n/a
On Wed, 3 Dec 2003 17:28:46 +0100, "Tim Clacy"
<no*******@nospamphaseone.nospamdk> 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 baseclass 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
Jul 22 '05 #10

P: n/a
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
Jul 22 '05 #11

P: n/a
tom_usenet wrote:
On Wed, 3 Dec 2003 17:28:46 +0100, "Tim Clacy"
<no*******@nospamphaseone.nospamdk> 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.
Jul 22 '05 #12

P: n/a
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!
Jul 22 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.