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