Да, но не напрямую:
template <typename Item, template <typename> class Container>
struct TList
{
typedef typename Container<Item>::type type;
};
Тогда вы можете определить различные политики контейнеров:
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;
Хотя и немного многословно. * Чтобы сделать что-то напрямую, вы быМне нужно взять маршрут, описанный Джеймсом , но, как он отмечает, это в конечном итоге очень негибко.
Однако с C ++ 0x мы можем сделать это просто прекрасно:
#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;
}
Отлично.К сожалению, нет никакого способа воспроизвести это в C ++ 03, кроме как через классы политики косвенного обращения, представленные, как описано выше.
* Я хочу подчеркнуть, что под «немного многословным» я имею в виду, что этонеортодоксальные».Правильное решение вашей проблемы - то, что делает стандартная библиотека, , как объясняет Джерри .Вы просто позволяете пользователю вашего адаптера контейнера указать весь тип контейнера напрямую:
template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
Но это оставляет большую проблему: что, если я не хочу, чтобы тип значения контейнера был Item
но something_else<Item>
?Другими словами, как я могу изменить тип значения существующего контейнера на что-то другое?В вашем случае это не так, поэтому читайте дальше, но в случае, если мы это сделаем, мы хотим перепривязать контейнер.
К сожалению для нас, контейнеры не имеют этогофункциональность, хотя распределители делают:
template <typename T>
struct allocator
{
template <typename U>
struct rebind
{
typedef allocator<U> type;
};
// ...
};
Это позволяет нам получить allocator<U>
при allocator<T>
.Как мы можем сделать то же самое для контейнеров без этой навязчивой утилиты?В C ++ 0x это просто:
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;
};
Учитывая std::vector<int>
, мы можем, например, выполнить rebind<float, std::vector<int>>::type
.В отличие от предыдущего решения C ++ 0x, его можно эмулировать в C ++ 03 с помощью макросов и итераций.
** Обратите внимание, что этот механизм можно сделать гораздо более мощным, например, указав, какие аргументысохранить, что связать, что связать себя, прежде чем использовать в качестве аргументов и т. д., но это оставлено в качестве упражнения для читателя.:)