Sí, pero no directamente:
template <typename Item, template <typename> class Container>
struct TList
{
typedef typename Container<Item>::type type;
};
Entonces podrá definir diferentes políticas de contenedores:
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;
Un poco detallado, sin embargo. * Para hacer las cosas directamente, necesitarías tomar the route described by James, pero como él nota esto es en última instancia muy inflexible.
Sin embargo, con C++ 0x podemos hacer esto muy bien:
#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;
}
perfecto. Desafortunadamente no hay forma de reproducir esto en C++ 03, excepto que a través de las clases de directivas de indirección se presentan como se describió anteriormente.
* Quiero hacer hincapié en que por "Un poco prolijo" quiero decir "esto es poco ortodoxo". La solución correcta para su problema es lo que hace la biblioteca estándar, as Jerry explains. Que acaba de dejar al usuario de su adaptador de contenedores especificar todo el tipo de contenedor directamente:
template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
Pero esto deja un gran problema: ¿qué pasa si no quiero el tipo de valor de que el contenedor sea Item
pero something_else<Item>
? En otras palabras, ¿cómo puedo cambiar el tipo de valor de un contenedor existente a otra cosa? En su caso, no es así, no siga leyendo, pero en el caso que lo hagamos, queremos volver a vincular un contenedor.
Por desgracia para nosotros, los contenedores no tienen esta funcionalidad, aunque asignadores hacen:
template <typename T>
struct allocator
{
template <typename U>
struct rebind
{
typedef allocator<U> type;
};
// ...
};
Esto nos permite obtener una allocator<U>
dieron un allocator<T>
. ¿Cómo podemos hacer lo mismo con los contenedores sin esta utilidad intrusiva? En C++ 0x, es fácil:
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;
};
Dado std::vector<int>
, podemos realizar rebind<float, std::vector<int>>::type
, por ejemplo. A diferencia del anterior C++ 0x solución, ésta puede ser emulado en C++ con las macros y 03 iteración ..
** Nota Este mecanismo se puede hacer mucho más potente, como especificar qué argumentos para mantener , que volver a enlazar, que volver a enlazar antes de usar como argumentos, etc., pero eso se deja como un ejercicio para el lector. :)
¿Quién utilizaría esta clase? ¿Por qué 'List' no puede usar' typedef vector/list/set- items'? ¿Cuál sería el propósito de una clase que, dado un tipo de contenedor y un tipo de valor, simplemente los junte? –
UncleBens
Re: la edición, todavía no veo por qué no puede escribir 'List> list;' etc –
UncleBens