In short: Because using a template template parameter is more restrictive* than using a type parameter without providing any advantages.
* By restrictive I mean that you may need a more complex stuff to obtain the same results than with a "simple" type parameter.
Why is there no advantages?
Your std::stack
probably has an attribute like this:
template <typename T, typename Container>
struct stack {
Container container;
};
If you replace Container
, by a template template parameter, why would you obtain?
template <typename T, template <typename...> class Container>
struct stack {
Container<T> container;
};
You are instantiating Container
only once and only for T
(Container<T>
), so there is no advantages for a template template parameter.
Why is it more restrictive?
With a template template parameter, you have to pass to std::stack
a template which expose the same signature, e.g.:
template <typename T, template <typename> class Container>
struct stack;
stack<int, std::vector> // Error: std::vector takes two template arguments
Maybe you could use variadic templates:
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>>
But what if I do not want to use the standard 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...
This is becoming a bit messy... What if I want to use my own container templates that takes 3/4/N parameters?
template <typename T,
template <typename... > class Container = std::vector,
typename... Args>
struct stack {
Container<T, Args...> container;
};
stack<int, MyTemplate, MyParam1, MyParam2> // Ok...
But, what if I want to use a non-templated containers?
struct foo { };
struct foo_container{ };
stack<foo, foo_container> // Error!
template <typename... >
using foo_container_template = foo_container;
stack<foo, foo_container_template> // Ok...
With a type parameter there are no such issues1:
stack<int>
stack<int, std::vector<int, MyAllocator<int>>
stack<int, MyTemplate<int, MyParam1, MyParam2>>
stack<foo, foo_container>
1 There are other cases which do not work with template template parameter such as using templates accepting a mix of type and non-type parameters in specific orders, for which you can create generic template template parameter, even using variadic templates.