Почему std:: stack не использует параметр шаблона шаблона?
Почему std::stack
и std::queue
используют параметр шаблона типа вместо параметра шаблона шаблона для своего базового типа контейнера?
то есть. почему stack
объявлен следующим образом:
template<typename T, typename Container = deque<T>>
class stack;
но не так:
template<typename T, template<typename> class Container = deque>
class stack;
?
Ответы
Ответ 1
Потому что типичные контейнеры, такие как std::vector
, имеют более одного аргумента шаблона. Не заботясь о том, что это шаблон, вы разрешаете использовать каждый вид контейнера.
Как
template<class T, class Allocator = std::allocator<T>> class vector;
вписывается в
template<typename> class Container
как это было бы в вашем stack
? (Подсказка: это не так!) Вам понадобятся специальные случаи для каждого числа и типа аргументов шаблона (тип против не-типа), которые вы хотите поддержать, что глупо, потому что они обычно не вносят никакого вклада больше информации, чем простой
typename Container
Обратите внимание, что для получения фактических аргументов шаблона, например. a std::vector
, у вас есть typedefs std::vector::value_type
и std::vector::allocator_type
, устраняя необходимость использования этих типов в явном виде, где вы действительно используете тип (т.е. Container
of stack
).
Ответ 2
Вкратце: использование параметра шаблона шаблона является более строгим *, чем использование параметра типа без предоставления каких-либо преимуществ.
* Под ограничением я подразумеваю, что вам может потребоваться более сложный материал для получения тех же результатов, чем с параметром "простого" типа.
Почему нет преимуществ?
Ваш std::stack
вероятно, имеет такой атрибут:
template <typename T, typename Container>
struct stack {
Container container;
};
Если вы замените Container
параметром шаблона шаблона, почему вы получили бы?
template <typename T, template <typename...> class Container>
struct stack {
Container<T> container;
};
Вы создаете экземпляр Container
только один раз и только для T
(Container<T>
), поэтому нет никаких преимуществ для параметра шаблона шаблона.
Почему это более ограничительно?
С параметром шаблона шаблона вы должны передать в std::stack
шаблон, который предоставляет такую же сигнатуру, например:
template <typename T, template <typename> class Container>
struct stack;
stack<int, std::vector> // Error: std::vector takes two template arguments
Может быть, вы могли бы использовать шаблоны variadic:
template <typename T, template <typename... > class Container>
struct stack {
Container<T> container;
};
stack<int, std::vector> // Ok, will use std::vector<int, std::allocator<int>>
Но что, если я не хочу использовать стандартный std::allocator<int>
?
template <typename T,
template <typename....> class Container = std::vector,
typename Allocator = std::allocator<T>>
struct stack {
Container<T, Allocator> container;
};
stack<int, std::vector, MyAllocator> // Ok...
Это становится немного грязно... Что если я захочу использовать свои собственные шаблоны контейнеров, которые принимают параметры 3/4/N?
template <typename T,
template <typename... > class Container = std::vector,
typename... Args>
struct stack {
Container<T, Args...> container;
};
stack<int, MyTemplate, MyParam1, MyParam2> // Ok...
Но что, если я хочу использовать контейнеры без шаблонов?
struct foo { };
struct foo_container{ };
stack<foo, foo_container> // Error!
template <typename... >
using foo_container_template = foo_container;
stack<foo, foo_container_template> // Ok...
С параметром типа нет таких проблем 1:
stack<int>
stack<int, std::vector<int, MyAllocator<int>>
stack<int, MyTemplate<int, MyParam1, MyParam2>>
stack<foo, foo_container>
1 Существуют и другие случаи, в которых не работает параметр шаблона шаблона, например использование шаблонов, принимающих сочетание типов и не типовых параметров в определенных заказах, для которых вы можете создать универсальный параметр шаблона шаблона, даже используя шаблоны с переменными параметрами.
Ответ 3
Использование параметра шаблона шаблона ограничило бы типы, которые вы могли бы использовать в качестве основного контейнера для тех, которые выставляют одну и ту же подпись шаблона. Эта форма позволяет произвольные типы, если они поддерживают ожидаемый интерфейс.
Ответ 4
Потому что он не компилирует:
std::deque
is not type
template <typename T> class std::deque
его тип
template<class T, class Alloc> class std::deque
Это, конечно, более общая проблема: даже если мы должны предоставить параметр шаблона Alloc
нашему шаблону класса stack
, класс теперь будет работать только с контейнерами, которые имеют ровно два аргумента шаблона типа. Это необоснованное ограничение.