What are template template parameters
for in template classes and functions, because you can pass them arguments that are templates using ordinary type parameters
?
Answer 1, authority 100%
It depends on what you mean by “passing them arguments that are templates using normal type parameters”.
-
A template is a template only as long as it has uncommitted parameters. When specific arguments are specified for all template parameters, this is no longer a template. A function template becomes a regular function, and a type template becomes a regular type. Therefore, on the one hand, when you pass a already specialized template via type parameters, then such a template is no longer template . This is just a type , a ready-made “frozen” concrete type, in which there is nothing boilerplate left. In general, it can no longer be “re-specialized” to another type.
And template template parameters are not final types cast in granite, they are still living movable templates . They can be freely specialized left and right with different arguments. For example
template & lt; template & lt; typename T, typename = std :: allocator & lt; T & gt; & gt; class Container & gt; struct S { Container & lt; int & gt; ints; Container & lt; double & gt; doubles; }; ... S & lt; std :: vector & gt; sv; S & lt; std :: list & gt; sl;
How are you going to do this through the “normal type parameter”?
-
On the other hand, templates can indeed be passed through “normal type parameters”. A template can be declared a member of an ordinary class, and then this normal class can be passed through the “normal type parameter”, thereby passing along with it the template “wrapped” in it. That is, from this point of view, template template parameters are redundant (as well as template non-type parameters) – all of them can be simulated using ordinary type parameters.
Answering your own question above
struct TraitsV { template & lt; typename T, typename A = std :: allocator & lt; T & gt; & gt; using Container = std :: vector & lt; T, A & gt ;; }; struct TraitsL { template & lt; typename T, typename A = std :: allocator & lt; T & gt; & gt; using Container = std :: list & lt; T, A & gt ;; }; template & lt; typename Traits & gt; struct S { typename Traits :: template Container & lt; int & gt; ints; typename Traits :: template Container & lt; double & gt; doubles; }; ... S & lt; TraitsV & gt; sv; S & lt; TraitsL & gt; sl;
It is not clear from your question which of these two points you are talking about.
Answer 2
For example to delegate the instantiation of this template to the target template. Those. give him the opportunity to independently choose the parameters for the transmitted template. For example:
template
& lt;
typename x_Value
, template
& lt;
typename xx_Value
, typename xx_Allocator
& gt; class x_Container
& gt; class t_Fancy
{
private: class
t_CustomAllocator {...};
private: using
t_Container = x_Container & lt; x_Value, t_CustomAllocator & gt ;;
};