This is a function template with a template template-parameter:
template <template <typename, typename> class TT>
TT<int, double>
make(int i, double d)
{
return TT<int, double>(i, d);
}
You specify a class or alias template which has two type parameters, and this function will use a specialization of this template, created using int
and double
as the template arguments. For example:
make< std::pair >(42, 4.2);
This returns a std::pair<int, double>
.
We can now "templatize" the (function) arguments of this function:
template <template <typename, typename> class TT, typename Arg0, typename Arg1>
TT<Arg0, Arg1>
make(Arg0 a0, Arg1 a1)
{
return TT<A0, A1>(a0, a1);
}
The template parameters Arg0
and Arg1
are intended to be deduced from the types of the (function) arguments used to call the function:
int i = 42;
double d = 4.2;
make< std::pair >(i, d); // returns a `std::pair<int, double>`
For more complex data types, we might want to use perfect forwarding:
make< std::pair >( 42, std::vector<int>(1000) );
This returns a std::pair<int, std::vector<int>>
.
The above definition of make
will move the temporary vector created via std::vector<int>(1000)
into the second function parameter. However, it will be copied from there into the object created via TT<A0, A1>(a0, a1)
.
We can change the definition of make
to implement perfect forwarding as follows:
template <template <typename, typename> class TT, typename Arg0, typename Arg1>
TT<Arg0, Arg1>
make(Arg0&& a0, Arg1&& a1)
{
return TT<A0, A1>(std::forward<A0>(a0), std::forward<A1>(a1));
}
The temporary vector created via std::vector<int>(1000)
will be moved into the object created within the return-statement.
Now, we can generalize this function template to N arguments; the template template-parameter also has to be generalized so that you can pass any class or alias template that takes some number of type parameters.
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}