Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > template specialization

Reply
Thread Tools

template specialization

 
 
Konstantin
Guest
Posts: n/a
 
      09-13-2008

I have two possible implementations of my class:

template <typename T>
class MyContainer
{
public:
typedef typename std::set<T>::const_iterator const_iterator;
void add( T id ) { data.insert(id); }
void remove( T id ) { data.erase(id); }
private:
std::set<T> data;
};


template <typename T>
class MyContainer
{
public:
typedef typename std::list<T>::const_iterator const_iterator;
void add( T id ) { data.push_back(id); }
void remove( T id ) { data.remove(id); }
private:
std::list<T> data;
};


which suggests that another parameter in the template could be added.

How to specialize the template correctly so that I could, for example, switch the underlying container:


typedef MyContainer<InstanceID, set>::const_iterator mycontainer_iterator;
MyContainer<InstanceID, set> mycontainer;

or

typedef MyContainer<InstanceID, list>::const_iterator mycontainer_iterator;
MyContainer<InstanceID, list> mycontainer;


--
Konstantin
 
Reply With Quote
 
 
 
 
Abhishek Padmanabh
Guest
Posts: n/a
 
      09-13-2008
On Sep 13, 5:51*pm, Konstantin <(E-Mail Removed)> wrote:
> I have two possible implementations of my class:
>
> template <typename T>
> class MyContainer
> {
> public:
> * * typedef typename std::set<T>::const_iterator const_iterator;
> * * void add( T id ) { data.insert(id); }
> * * void remove( T id ) { data.erase(id); }
> private:
> * * std::set<T> data;
>
> };
>
> template <typename T>
> class MyContainer
> {
> public:
> * * typedef typename std::list<T>::const_iterator const_iterator;
> * * void add( T id ) { data.push_back(id); }
> * * void remove( T id ) { data.remove(id); }
> private:
> * * std::list<T> data;
>
> };
>
> which suggests that another parameter in the template could be added.
>
> How to specialize the template correctly so that I could, for example, switch the underlying container:


It's not clear what your problem is. If you want to write container
adaptors, try looking at some examples of those in the standard
library for example, std:riority_queue<>. You would need an extra
template parameter for the container to choose as you rightly
observerd. But I am not sure what specialization you are asking of?
Are you saying your template should be instantiable only on std::set
and std::list?

>
> typedef MyContainer<InstanceID, set>::const_iterator mycontainer_iterator;
> MyContainer<InstanceID, set> mycontainer;
>
> or
>
> typedef MyContainer<InstanceID, list>::const_iterator mycontainer_iterator;
> MyContainer<InstanceID, list> mycontainer;


 
Reply With Quote
 
 
 
 
Konstantin
Guest
Posts: n/a
 
      09-13-2008
Abhishek Padmanabh wrote:
> On Sep 13, 5:51 pm, Konstantin <(E-Mail Removed)> wrote:
>> I have two possible implementations of my class:
>>
>> template <typename T>
>> class MyContainer
>> {
>> public:
>> typedef typename std::set<T>::const_iterator const_iterator;
>> void add( T id ) { data.insert(id); }
>> void remove( T id ) { data.erase(id); }
>> private:
>> std::set<T> data;
>>
>> };
>>
>> template <typename T>
>> class MyContainer
>> {
>> public:
>> typedef typename std::list<T>::const_iterator const_iterator;
>> void add( T id ) { data.push_back(id); }
>> void remove( T id ) { data.remove(id); }
>> private:
>> std::list<T> data;
>>
>> };
>>
>> which suggests that another parameter in the template could be added.
>>
>> How to specialize the template correctly so that I could, for example, switch the underlying container:

>
> It's not clear what your problem is. If you want to write container
> adaptors, try looking at some examples of those in the standard
> library for example, std:riority_queue<>. You would need an extra
> template parameter for the container to choose as you rightly
> observerd. But I am not sure what specialization you are asking of?
> Are you saying your template should be instantiable only on std::set
> and std::list?



Yes.



>> typedef MyContainer<InstanceID, set>::const_iterator mycontainer_iterator;
>> MyContainer<InstanceID, set> mycontainer;
>>
>> or
>>
>> typedef MyContainer<InstanceID, list>::const_iterator mycontainer_iterator;
>> MyContainer<InstanceID, list> mycontainer;

>

 
Reply With Quote
 
mqrk
Guest
Posts: n/a
 
      09-13-2008
The simplest (and probably the best) solution is like this:

template < class, template < class > class > class MyContainer;

template <typename T>
class MyContainer< T, std::set >
{
public:
typedef typename std::set<T>::const_iterator const_iterator;
void add( T id ) { data.insert(id); }
void remove( T id ) { data.erase(id); }
private:
std::set<T> data;

};

template <typename T>
class MyContainer< T, std::list >
{
public:
typedef typename std::list<T>::const_iterator const_iterator;
void add( T id ) { data.push_back(id); }
void remove( T id ) { data.remove(id); }
private:
std::list<T> data;

};

This solution doesn't scale particularly well. If you're doing this
with more than just two container types, you might just want to have
one definition of MyContainer, and handle the rest with policies. It
might look something like this: (this is just a rough outline)

template < class Container > class DefaultAccessPolicy;

template < typename T, template <typename> class Container, template <
class > class AccessPolicy = DefaultAccessPolicy >
class MyContainer
{
public:
typedef typename Container::const_iterator const_iterator;
void add( T id ) { AccessPolicy< Container<T> >::add( &data,
id ); }
void remove( T id ) { AccessPolicy< Container<T> >::remove( &data,
id ); }
private:
Container<T> data;
};

template < typename T >
class DefaultAccessPolicy< std::list<T> >
{
public:
static void add( std::list<T>* l, T t ) { l->push_back( t ); }
static void remove( std::list<T>* l, T t ) { l->remove( t ); }
};

//Ditto for std::set and so on

Now you only have one definition of the main class, which may cut down
on maintenance. For example, when you decide that you don't only need
const_iterator, but want a plain iterator as well, you only have to
modify one class. Also, if you later decide you want to change how a
particular instance of a container-adapter operates (maybe a list that
uses push_front, or only removes the first match), you just have to
write a new policy.

Regards,
Mark McKenna
 
Reply With Quote
 
Konstantin
Guest
Posts: n/a
 
      09-13-2008

Yes, this is what I was looking for. Thanks.


mqrk wrote:
> The simplest (and probably the best) solution is like this:
>
> template < class, template < class > class > class MyContainer;
>
> template <typename T>
> class MyContainer< T, std::set >
> {
> public:
> typedef typename std::set<T>::const_iterator const_iterator;
> void add( T id ) { data.insert(id); }
> void remove( T id ) { data.erase(id); }
> private:
> std::set<T> data;
>
> };
>
> template <typename T>
> class MyContainer< T, std::list >
> {
> public:
> typedef typename std::list<T>::const_iterator const_iterator;
> void add( T id ) { data.push_back(id); }
> void remove( T id ) { data.remove(id); }
> private:
> std::list<T> data;
>
> };
>
> This solution doesn't scale particularly well. If you're doing this
> with more than just two container types, you might just want to have
> one definition of MyContainer, and handle the rest with policies. It
> might look something like this: (this is just a rough outline)
>
> template < class Container > class DefaultAccessPolicy;
>
> template < typename T, template <typename> class Container, template <
> class > class AccessPolicy = DefaultAccessPolicy >
> class MyContainer
> {
> public:
> typedef typename Container::const_iterator const_iterator;
> void add( T id ) { AccessPolicy< Container<T> >::add( &data,
> id ); }
> void remove( T id ) { AccessPolicy< Container<T> >::remove( &data,
> id ); }
> private:
> Container<T> data;
> };
>
> template < typename T >
> class DefaultAccessPolicy< std::list<T> >
> {
> public:
> static void add( std::list<T>* l, T t ) { l->push_back( t ); }
> static void remove( std::list<T>* l, T t ) { l->remove( t ); }
> };
>
> //Ditto for std::set and so on
>
> Now you only have one definition of the main class, which may cut down
> on maintenance. For example, when you decide that you don't only need
> const_iterator, but want a plain iterator as well, you only have to
> modify one class. Also, if you later decide you want to change how a
> particular instance of a container-adapter operates (maybe a list that
> uses push_front, or only removes the first match), you just have to
> write a new policy.
>
> Regards,
> Mark McKenna

 
Reply With Quote
 
Konstantin
Guest
Posts: n/a
 
      09-15-2008
mqrk wrote:
> The simplest (and probably the best) solution is like this:
>



The problem still remains:


template <typename T> struct Container< T, std::set >
{
std::set<T> data;
};

template <typename T> struct Container< T, std::list >
{
std::list<T> data;
};


These are specializations, and one needs to write a primary template.
However, std::set template has three parameters: set<Key, Compare,
Alloc>, and std::list has only two: list<Type, Alloc>

Thus, if the primary template is

template < typename, template < typename, typename, typename > class >
class Container;

then the second specialization yields an error ("error C3201: the
template parameter list for class template 'std::list' does not match
the template parameter list for template parameter ...")

and if the primary template is

template < typename T, template<typename, typename> class >
class Container;

then the "set" template yields an error, and "list" works fine.




The same problem is in the solution with policies: the line
template <typename> class Container
in
template < typename T,
template <typename> class Container,
template <class > class AccessPolicy = DefaultAccessPolicy >
class MyContainer

will match neither std::set nor std::list for the same reason; adding
more arguments, e.g. template <typename,typename> class Container breaks
generality.


Is there a mechanism to reconcile these two? (E.g. something like
var-arg template arguments...)


Konstantin.
 
Reply With Quote
 
mqrk
Guest
Posts: n/a
 
      09-15-2008
On Sep 14, 8:40 pm, Konstantin <(E-Mail Removed)> wrote:
> ... if the primary template is
> template < typename T, template<typename, typename> class >
> class Container;
>
> then the "set" template yields an error, and "list" works fine.


Sorry about that. It works with gcc 4.1.3 as long as there are fewer
template parameters in the template template parameter then there are
in the template template argument. I didn't know this wasn't
standard.

> Is there a mechanism to reconcile these two? (E.g. something like
> var-arg template arguments...)


Not that I can think of. There will probably be variadic templates in
the next standard though (for all the good that does you now).
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      09-15-2008
mqrk wrote:

> On Sep 14, 8:40 pm, Konstantin <(E-Mail Removed)> wrote:
>> ... if the primary template is
>> template < typename T, template<typename, typename> class >
>> class Container;
>>
>> then the "set" template yields an error, and "list" works fine.

>
> Sorry about that. It works with gcc 4.1.3 as long as there are fewer
> template parameters in the template template parameter then there are
> in the template template argument. I didn't know this wasn't
> standard.
>
>> Is there a mechanism to reconcile these two? (E.g. something like
>> var-arg template arguments...)

>
> Not that I can think of. There will probably be variadic templates in
> the next standard though (for all the good that does you now).


The ad-hoc way would be to define

template < typename T, typename A, typename C >
struct Set : public std::set< T, A, C > {
// some forwarding constructors (templated)
}

template < typename T, typename A, typename C >
struct List : public std::list< T, A > {
// some forwarding constructors (templated)
}

and then use these instead of std::set and std::list.


Best

Kai-Uwe Bux
 
Reply With Quote
 
Konstantin
Guest
Posts: n/a
 
      09-15-2008

Oh, great! Thank you all.

Konstantin.



Kai-Uwe Bux wrote:
> mqrk wrote:
>
>> On Sep 14, 8:40 pm, Konstantin <(E-Mail Removed)> wrote:
>>> ... if the primary template is
>>> template < typename T, template<typename, typename> class >
>>> class Container;
>>>
>>> then the "set" template yields an error, and "list" works fine.

>> Sorry about that. It works with gcc 4.1.3 as long as there are fewer
>> template parameters in the template template parameter then there are
>> in the template template argument. I didn't know this wasn't
>> standard.
>>
>>> Is there a mechanism to reconcile these two? (E.g. something like
>>> var-arg template arguments...)

>> Not that I can think of. There will probably be variadic templates in
>> the next standard though (for all the good that does you now).

>
> The ad-hoc way would be to define
>
> template < typename T, typename A, typename C >
> struct Set : public std::set< T, A, C > {
> // some forwarding constructors (templated)
> }
>
> template < typename T, typename A, typename C >
> struct List : public std::list< T, A > {
> // some forwarding constructors (templated)
> }
>
> and then use these instead of std::set and std::list.
>
>
> Best
>
> Kai-Uwe Bux

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Full specialization of a member function template of a class template Dave C++ 4 06-04-2010 12:15 PM
template specialization overriding non-specialization? Joseph Turian C++ 2 04-16-2006 02:46 PM
Template specialization for templated and primitive type template parameters case2005 C++ 3 02-13-2005 06:53 PM
template specialization of a template class pit3k C++ 8 02-09-2005 02:39 AM
Specialization of a template within template David B. Held C++ 2 10-26-2003 11:59 AM



Advertisments