The following code represents a container based on std::vector
template <typename Item>
struct TList
{
typedef std::vector <Item> Type;
};
template <typename Item>
class List
{
private
typename TList <Item>::Type items;
....
}
int main()
{
List <Object> list;
}
Is it possible to templatize std::vector and create a general container, something like that?
template <typename Item, typename stl_container>
struct TList
{
typedef stl_container<Item>;
};
where stl_container represents std::vector, std::list, std::set...? I would like to choose the type of container at the time of the creation.
List <Object, std::vector> list; //vector of objects, not a real code
List <Object, std::vector> list; //list of objects, not a real code
Thanks for your answers...
Updated question:
I tried the following code but there are errors:
#include <vector>
template <typename Item, typename Container>
struct TList
{
typedef typename Container <Item>::type type; //Error C2059: syntax error : '<', Error C2238: unexpected token(s) preceding ';
};
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
int _tmain(int argc, _TCHAR* argv[])
{
TList <int, vector_container> v;
TList <int, map_container> m;
}
Yes, but not directly:
template <typename Item, template <typename> class Container>
struct TList
{
typedef typename Container<Item>::type type;
};
Then you can define different container policies:
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
template <typename T>
struct map_container
{
typedef std::map<T, std::string> type;
};
TList<int, vector_container> v;
TList<int, map_container> m;
A bit verbose, though.* To do things directly, you'd need to take the route described by James, but as he notes this is ultimately very inflexible.
However, with C++0x we can do this just fine:
#include <map>
#include <vector>
template <typename Item,
template <typename...> class Container, typename... Args>
struct TList
{
// Args lets the user specify additional explicit template arguments
Container<Item, Args...> storage;
};
int main()
{
TList<int, std::vector> v;
TList<int, std::map, float> m;
}
Perfect. Unfortunately there's no way to reproduce this in C++03, except via the indirection policy classes introduce as described above.
*I want to emphasize that by "A bit verbose" I mean "this is unorthodox". The correct solution for your problem is what the standard library does, as Jerry explains. You just let the user of your container adapter specify the entire container type directly:
template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
But this leaves a big problem: what if I don't want the value type of the container to be Item but something_else<Item>? In other words, how can I change the value type of an existing container to something else? In your case you don't, so read no further, but in the case we do, we want to rebind a container.
Unfortunately for us, the containers don't have this functionality, though allocators do:
template <typename T>
struct allocator
{
template <typename U>
struct rebind
{
typedef allocator<U> type;
};
// ...
};
This allows us to get an allocator<U> given an allocator<T>. How can we do the same for containers without this intrusive utility? In C++0x, it's easy:
template <typename T, typename Container>
struct rebind; // not defined
template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
// assumes the rest are filled with defaults**
typedef Container<T> type;
};
Given std::vector<int>, we can perform rebind<float, std::vector<int>>::type, for example. Unlike the previous C++0x solution, this one can be emulated in C++03 with macros and iteration..
**Note this mechanism can be made much more powerful, like specifying which arguments to keep, which to rebind, which to rebind themselves before using as arguments, etc., but that's left as an exercise for the reader. :)
I'm a bit puzzled why some very smart (and competent) people are saying no.
Unless I've misread your question, what you're trying to accomplish is virtually identical to the "container adapters" in the standard library. Each provides an interface to some underlying container type, with the container type that will be used provided as a template parameter (with a default value).
For example, a std::stack uses some other container (e.g., std::deque, std::list or std::vector) to hold the objects, and std::stack itself just provides a simplified/restricted interface for when you just want to use stack operations. The underlying container that will be used by the std::stack is provided as a template parameter. Here's how the code looks in the standard:
namespace std {
template <class T, class Container = deque<T> >
class stack {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef Container container_type;
protected:
Container c;
public:
explicit stack(const Container& = Container());
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
}
Of course, perhaps I've just misunderstood the question -- if so, I apologize in advance to the people with whom I'm (sort of) disagreeing.
Yes and no.
You can use a template template parameter, e.g.,
template <typename Item, template <typename> class Container>
struct TList { /* ... */ };
However, in general, template template parameters are not particularly useful because the number and types of the template parameters have to match. So, the above would not match std::vector because it actually has two template parameters: one for the value type and one for the allocator. A template template parameter can't take advantage of any default template arguments.
To be able to use the std::vector template as an argument, TList would have to be declared as:
template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };
However, with this template, you wouldn't be able to use the std::map template as an argument because it has four template parameters: the key and value types, the allocator type, and the comparator type.
Usually it is much easier to avoid template template parameters because of this inflexibility.
well, you can hack it up with a macro:
template <typename T, typename stl_container = std::vector<T> >
struct TList
{
typedef stl_container Type;
};
#define TLIST(T, C) TList<T, C<T> >
TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;
Is it possible to templatize std::vector and create a general container, something like that?
No. You would have to templatize the function or object using the container -- you couldn't templatize the container itself.
For example. consider a typical std::find:
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
for ( ;first!=last; first++) if ( *first==value ) break;
return first;
}
This works for any container, but doesn't need a tempalte with the container at all.
Also, given that it looks what you're trying to do is make container independent code, you might want to buy or borrow yourself a copy of Scott Meyers' Effective STL and read Item 2: Beware the illusion of container-independent code.
You can use template template parameters as others have mentioned here. The main difficulty with this is not that dissimilar container types have dissimilar template parameters, but that the standard allows the standard containers, like vector, to have template parameters in addition to the documented, necessary ones.
You can get around this by providing your own subclass types that accept the appropriate template parameters and let any extras (which have to have defaults) be filled in my the implementation:
template < typename T > struct simple_vector : std::vector<T> {};
Or you can use the templated typedef idiom:
template < typename T > struct retrieve_vector { typedef std::vector<T> type; };
Related
I want to create a template class which has an iterator of a STL container as a member. That is how far I got:
#include <iostream>
#include <vector>
using namespace std;
template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
ClassHoldingAnIteratorToAStandardContainer(){}
typename StdLibContainer<Element*>::iterator std_lib_iterator;
};
int main()
{
vector<int> vec{1,2,3};
ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
//DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
return 0;
}
Could you explain the syntax template <typename> class StdLibContainer?
I found it somewhere on stackoverflow. BUt I don't understand it.
How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’
In the above example i want to assign holding_iterator_to_vec vec.begin().
template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:
template<class T> struct Foo {};
// or
template<typename T> struct Foo {};
Do not ask me why! However, the same was not true for template template parameters:
template <template <class> typename T> struct Foo {};
was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.
As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.
To make it universal, use
template<template <class...> class Container> struct Foo{};
Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:
template<typename iterator>
struct iterator_wrapper {
iterator iter;
};
Thats the minimum you need to have an iterator as member :).
I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....
#include <iterator>
#include <vector>
#include <iostream>
template<typename iterator>
struct iterator_wrapper {
using value_type = typename std::iterator_traits<iterator>::value_type;
iterator iter;
bool operator!=(const iterator& other) { return iter != other;}
iterator_wrapper& operator++(){
++iter;
return *this;
}
const value_type& operator*() { return *iter; }
};
template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) {
return {it};
}
int main() {
std::vector<int> vec{1,2,3};
auto it = wrap_iterator(vec.begin());
for (;it != vec.end();++it) std::cout << *it;
}
Also there is a problem in your code.
typename StdLibContainer<Element*>::iterator
is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:
template <typename container,
typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) {
return {c.begin()};
}
which makes creating an iterator_wrapper as simple as
auto x = wrap_begin(vec);
Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.
I have a question about template template parameters:
Let's consider the following class:
template<typename T, template<class, class=std::allocator<T> > class UnderlyingContainerType = std::vector>
class MyContainer
{
public:
T Value1;
T Value2;
UnderlyingContainerType<T> Container;
MyContainer() {}
/* methods implementation goes here */
};
In this example, MyContainer is a container chat uses an underlying STL-compatible container to do whatever stuff.
Declaring the underlying container type as a template template parameters, instead of a regular template argument, allows handy usage of the class MyContainer, such as:
MyContainer<int> MCV; //implicitly using vector
MyContainer<int, std::list> MCL; //no need to write std::list<int> thanks to the
//template template parameters
Now, while this would work perfectly with most of the STL-container, such as std::vector, std::deque, std::list, and so forth, it would not work, for example, with std::array provided in c++11.
The reason is that std::array has a different signature of template parameters than vector. Specifically, they are:
std::vector<class T, class allocator = std::allocator<T> >
std::array<class T, int N>
MY question is if there is a way to generalize the class MyContainer, so that the underlying container can be std::array as well.
I thank you in advance.
The commonality between the interfaces of vector and array are limited to the element type. Your container should reflect that:
template<typename T, template<typename> class underlying_container>
struct container
{
underlying_container<T> storage;
};
Usage now requires a tiny trick:
template<typename T> using vec = vector<T>;
template<typename T> using arr2 = array<T, 2>;
Note that vec, unlike vector, has a fixed allocator and that arr2, unlike array, has a fixed size.
Usage is now simple:
container<int, vec> a;
container<double, arr2> b;
See the example in action.
Alternatively, if you prefer to match up the interface to that used by vector, just add a template alias for array that instantiates the size and adds an unused type parameter:
template<typename T, typename> using arr2 = array<T, 2>;
See it in action.
I don't know how to achieve exactly, what you want. But if you don't require the ability to write MyContainer<int> MCV; you could use
template<class UnderlyingContainerType, class T = typename UnderlyingContainerType::value_type>
class MyContainer
{
public:
T Value1;
T Value2;
UnderlyingContainerType Container;
MyContainer() {}
/* methods implementation goes here */
};
int main() {
MyContainer<std::vector<int>> MCV{};
MyContainer<std::array<int, 5>> MCA{};
}
Which is not more to type than MyContainer<int, std::vector> MCV;
Also you can of course still add an alias for your vector based version:
template<class T>
using MyContainerV = MyContainer < std::vector<T> > ;
//a class template to do something to STL container
template<typename T/*should be a STL container*/,typename Ele/*the type of element*/>
struct foo{
T a_container_with_an_element(){
T con;
Ele e;
con.push_back(++++e);
return con;
}
As you can see, it's really foolish to put the element's type into templates' parameter because it's already contained in the container's type.
So, is there any magic to get the element's type out of T?
Lots of Thx :-)
If the container is a standard library container, the name of the element is an embedded name of the container as follows:
typedef typename T::value_type type;
The standard container's have a few standard names in them (for example, see vector on cppreference) and the C++ standard §23.2.
X::value_type
X::reference
X::const_reference
X::iterator
X::const_iterator
X::difference_type
X::size_type
Every "container" in the standard library, tries to adhere to the Container concept. This concepts requires that, given a container T:
T::value_type is the type of the container element
T::reference is a reference type to the container element
T::const_reference is a constant reference type to the container element
In your specific example, you can extract the element type by:
template<typename Container>
struct foo {
Container a_container_with_an_element(){
Container con;
typename Container::value_type e;
con.push_back(++++e);
return con;
}
In your special case where you know that T is a STL container Naill's answer is correct, use the nested types in the container.
If however you want a more generic "I know I am getting a template as T and I want the type of the first parameter of that template" case you can get the type through template specialization:
template<typename T>
struct MyFirstElement;
template<template<typename...> class T_Container, typename T_Type, typename... Ts>
struct MyFirstElement<T_Container<T_Type,Ts...>>{
using Type = T_Type;
};
//unit test
using MustBeInt = typename MyFirstElement<std::vector<int>>::Type;
using MustBeLong = typename MyFirstElement<std::map<long,float>>::Type;
static_assert(std::is_same<MustBeInt,int>::value,"");
static_assert(std::is_same<MustBeLong,long>::value,"");
//this works too even though its not an STL container
template<typename T, typename U, typename Z>
struct MyCrazyContainer{};
static_assert(std::is_same<typename MyFirstElement<MyCrazyContainer<bool,long,float>>::Type,bool>::value,"");
here is a live example: http://ideone.com/OxhSOc
As Jarod42 pointed out this will only work with templates which are "regular" i.e. only have types as parameters. std::array for example breatks this because it has an int as a second parameter.
If T should be an STL container you could use a template-template parameter. It must be a container that supports push_back() and we will incorporate the fact that STL containers contain a 2nd "allocator" parameter.
In that case you can use
template< template<typename, typename> class Con,
typename Ele, typename Alloc = std::allocator<Ele> >
struct foo
{
typedef Con<Ele, Alloc> container_type;
typedef Ele value_type;
container_type a_container_with_an_element()
{
container_type con;
value_type e;
con.push_back( e ); // or modify e first but not ++++e
return con;
}
};
Your code would then do
foo< std::vector, int > myfoo;
std::vector<int> myvec = myfoo.a_container_with_an_element();
If you want just one template parameter
template< typename Con >
struct foo
{
typedef typename Con::value_type value_type;
Con a_container_with_an_element()
{
Con con;
value_type e;
con.push_back( e ); // or modify e first but not ++++e
return con;
}
};
and usage:
foo<std::vector<int> > myfoo;
std::vector<int> myvec = myfoo.a_container_with_an_element();
Note that in this example you can also do foo<std::vector<int> >::Ele to get the element type. You could make a typedef for the container type too. Often used in templates. (You need typename when the template is not fully qualified. So foo<std::vector<int>> is fully qualified and doesn't need it there.
Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containers are in fact templates, this template has a template param. This is what I had to write:
#include <vector>
#include <list>
using namespace std;
template < template <class,class> class C, typename T>
class ExampleTemplate {
C<T,allocator<T> > items;
public:
....
};
main()
{
ExampleTemplate<list,int> a;
ExampleTemplate<vector,float> b;
}
You may ask what is the "allocator" thing about. Well, Initially, I tried the obvious thing...
template < template <class> class C, typename T>
class ExampleTemplate {
C<T> items;
};
...but I unfortunately found out that the default argument of the allocator...
vector<T, Alloc>
list<T, Alloc>
etc
...had to be explicitely "reserved" in the template declaration.
This, as you can see, makes the code uglier, and forces me to reproduce the default values of the template arguments (in this case, the allocator).
Which is BAD.
EDIT: The question is not about the specific problem of containers - it is about "Default values in templates with template arguments", and the above is just an example. Answers depending on the knowledge that STL containers have a "::value_type" are not what I am after. Think of the generic problem: if I need to use a template argument C in a template ExampleTemplate, then in the body of ExampleTemplate, do I have to reproduce the default arguments of C when I use it? If I have to, doesn't that introduce unnecessary repetition and other problems (in this case, where C is an STL container, portability issues - e.g. "allocator" )?
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes with a non-STL-compliant container would need to specialize the ValueTypeOf traits class.
I would propose to create adapters.
Your class should be created with the exact level of personalization that is required by the class:
template <template <class> C, template T>
class Example
{
typedef T Type;
typedef C<T> Container;
};
EDIT: attempting to provide more is nice, but doomed to fail, look at the various expansions:
std::vector<T>: std::vector<T, std::allocator<T>>
std::stack<T>: std::stack<T, std::deque<T>>
std::set<T>: std::set<T, std::less<T>, std::allocator<T>>
The second is an adapter, and so does not take an allocator, and the third does not have the same arity. You need therefore to put the onus on the user.
If a user wishes to use it with a type that does not respect the expressed arity, then the simplest way for him is to provide (locally) an adapter:
template <typename T>
using Vector = std::vector<T>; // C++0x
Example<Vector, bool> example;
I am wondering about the use of parameter packs (variadic templates) here... I don't know if declaring C as template <class...> C would do the trick or if the compiler would require a variadic class then.
You have to give the full template signature, including default parameters, if you want to be able to use the template template parameter the usual way.
template <typename T, template <class U, class V = allocator<U> > class C>
class ExampleTemplate {
C<T> items;
public:
....
};
If you want to handle other containers that the one from the STL, you can delegate container construction to a helper.
// Other specialization failed. Instantiate a std::vector.
template <typename T, typename C>
struct make_container_
{
typedef std::vector<T> result;
};
// STL containers
template <typename T, template <class U, class V = allocator<U> > class C>
struct make_container_<T,C>
{
typedef C<T> result;
};
// Other specializations
...
template <typename T, typename C>
class ExampleTemplate {
make_container_<T,C>::result items;
public:
....
};
I think, it is required to reproduce all template parameters, even default. Note, that Standard itself does not use template template parameters for containter adaptors, and prefers to use regular template parameters:
template < class T , class Container = deque <T > > class queue { ... };
template < class T , class Container = vector <T>, class Compare = less < typename Container :: value_type > > class priority_queue { ... };
The following code will allow you to do something like you're asking for. Of course, this won't work with standard containers, since this has to already be part of the template class that's being passed into the template.
/* Allows you to create template classes that allow users to specify only some
* of the default parameters, and some not.
*
* Example:
* template <typename A = use_default, typename B = use_default>
* class foo
* {
* typedef use_default_param<A, int> a_type;
* typedef use_default_param<B, double> b_type;
* ...
* };
*
* foo<use_default, bool> x;
* foo<char, use_default> y;
*/
struct use_default;
template<class param, class default_type>
struct default_param
{
typedef param type;
};
template<class default_type>
struct default_param<use_default, default_type>
{
typedef default_type type;
};
But I don't really think this is what you're looking for. What you're doing with the containers is unlikely to be applicable to arbitrary containers as many of them will have the problem you're having with multiple default parameters with non-obvious types as defaults.
As the question exactly described the problem I had in my code (--I'm using Visual Studio 2015), I figured out an alternative solution which I wanted to share.
The idea is the following: instead of passing a template template parameter to the ExampleTemplate class template, one can also pass a normal typename which contains a type DummyType as dummy parameter, say std::vector<DummyType>.
Then, inside the class, one replace this dummy parameter by something reasonable. For replacement of the typethe following helper classes can be used:
// this is simply the replacement for a normal type:
// it takes a type T, and possibly replaces it with ReplaceByType
template<typename T, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type
{
using type = std::conditional_t<std::is_same<T, ReplaceWhatType>::value, ReplaceByType, T>;
};
// this sets up the recursion, such that replacement also happens
// in contained nested types
// example: in "std::vector<T, allocator<T> >", both T's are replaced
template<template<typename ...> class C, typename ... Args, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type<C<Args ...>, ReplaceWhatType, ReplaceByType>
{
using type = C<typename replace_type<Args, ReplaceWhatType, ReplaceByType>::type ...>;
};
// an alias for convenience
template<typename ... Args>
using replace_type_t = typename replace_type<Args ...>::type;
Note the recursive step in replace_type, which takes care that types nested in other classes are replaced as well -- with this, for example, in std::vector<T, allocator<T> >, both T's are replaced and not only the first one. The same goes for more than one nesting hierarchy.
Next, you can use this in your ExampleTemplate-class,
struct DummyType {};
template <typename C, typename T>
struct ExampleTemplate
{
replace_type_t<C, DummyType, T> items;
};
and call it via
int main()
{
ExampleTemplate<std::vector<DummyType>, float> a;
a.items.push_back(1.0);
//a.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::list<DummyType>, float> b;
b.items.push_back(1.0);
//b.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::map<int, DummyType>, float> c;
c.items[0]=1.0;
//c.items[0]="Hello"; // prints an error message which shows that DummyType is replaced correctly
}
DEMO
Beside the not-that-nice syntac, this has the advantage that
It works with any number of default template parameters -- for instance, consider the case with std::map in the example.
There is no need to explicitly specify any default template parameters whatsoever.
It can be easily extended to more dummy parameters (whereas then it probably should not be called by users ...).
By the way: Instead of the dummy type you can also use the std::placeholder's ... just realized that it might be a bit nicer.
I am pondering about partial specialization. While I understand the idea, I haven't seen any real-world usage of this technique. Full specialization is used in many places in STL so I don't have a problem with that. Could you educate me about a real-world example where partial specialization is used? If the example is in STL that would be superior!
C++0x comes with unique_ptr which is a replacement for auto_ptr which is going to be deprecated.
If you use unique_ptr with an array type, it uses delete[] to free it, and to provide operator[] etc. If you use it with a non-array type, it uses delete. This needs partial template specialization like
template<typename T>
struct my_unique_ptr { ... };
template<typename T>
struct my_unique_ptr<T[]> { ... };
Another use (although a very questionable) is std::vector<bool, Allocator> in the standard library. The bool specialization uses a space optimization to pack bools into individual bits
template<typename T, typename Allocator = std::allocator<T> >
struct vector { ... };
template<typename Allocator>
struct vector<bool, Allocator> { ... };
Yet another use is with std::iterator_traits<T>. Iterators are required to define the nested typedefs value_type, reference and others to the correct types (for a const iterator, reference would usually be T const&, for example) so algorithms may use them for their work. The primary template uses type-members of the iterator type in turn
template<typename T>
struct iterator_traits {
typedef typename T::value_type value_type;
...
};
For pointers, that of course doesn't work. There is a partial specialization for them
template<typename T>
struct iterator_traits<T*> {
typedef T value_type;
...
};
In some stl implementations collections like std::vector and std::list use partial template specialization to reduce the amount of code generated for collections of pointers.
Each instantiation of a template for a type T creates new code. However pointer types are effectively all the same so generating new code for every type is a waste. This can be reduced by implementing the private part of pointer collections with void pointers and then casting these to the appropriate type in the public interface. This greatly reduces the code generated for pointer collections.
I think this is covered in Effective STL.
Taken from MSDN (Partial Specialization of Class Templates (C++))
// partial_specialization_of_class_templates.cpp
template <class T> struct PTS {
enum {
IsPointer = 0,
IsPointerToDataMember = 0
};
};
template <class T> struct PTS<T*> {
enum {
IsPointer = 1,
IsPointerToDataMember = 0
};
};
template <class T, class U> struct PTS<T U::*> {
enum {
IsPointer = 0,
IsPointerToDataMember = 1
};
};