Why do std::stack
and std::queue
use type template parameter instead of template template parameter for their underlying container type?
i.e. why is stack
declared like this:
template<typename T, typename Container = deque<T>> class stack;
but not like this:
template<typename T, template<typename> class Container = deque> class stack;
?
Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.
Correct Option: C. The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.
There is no difference. typename and class are interchangeable in the declaration of a type template parameter.
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
Because typically containers like std::vector
have more than one template argument. By not caring about it being a template, you allow every kind of container to be used.
How would
template<class T, class Allocator = std::allocator<T>> class vector;
fit onto
template<typename> class Container
as you would have it in your stack
? (Hint: it doesn't!) You'd need special cases for each number and kind of template arguments (type vs. non-type) you'd want to support, which is silly, because these typically don't contribute any more information than a simple
typename Container
Note that to get at the actual template arguments of e.g. a std::vector
, you have the typedefs std::vector::value_type
and std::vector::allocator_type
, removing the need of having these types available explicitly where you actually use the type (i.e. the Container
of stack
).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With