template specialization

K

Konstantin

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;
 
A

Abhishek Padmanabh

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::priority_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?
 
K

Konstantin

Abhishek said:
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::priority_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.
 
M

mqrk

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
 
K

Konstantin

mqrk said:
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.
 
M

mqrk

... 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).
 
K

Kai-Uwe Bux

mqrk said:
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.


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
 
K

Konstantin

Oh, great! Thank you all.

Konstantin.



Kai-Uwe Bux said:
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
 

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,012
Latest member
RoxanneDzm

Latest Threads

Top