Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::stack not use template template parameter?

Tags:

c++

templates

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; 

?

like image 973
Hedede Avatar asked Aug 02 '16 13:08

Hedede


People also ask

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

Which parameter is allowed for non-type template?

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.

What is the difference between template Typename T and template T?

There is no difference. typename and class are interchangeable in the declaration of a type template parameter.

Can template have default parameters?

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 { };


2 Answers

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).

like image 121
rubenvb Avatar answered Oct 15 '22 01:10

rubenvb


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.

like image 38
Holt Avatar answered Oct 15 '22 02:10

Holt