Something like this? Using a type transformation based on partial specialization:
#include<type_traits>
template<template<typename...> class, typename>
struct with_tmpl_args_of;
template<template<typename...> class OtherTmpl, template<typename...> class Tmpl, typename... Args>
struct with_tmpl_args_of<OtherTmpl, Tmpl<Args...>> {
using type = OtherTmpl<Args...>;
};
template<template<typename...> class OtherTmpl, typename T>
using with_tmpl_args_of_t = typename with_tmpl_args_of<OtherTmpl, T>::type;
// example
template<class ... Types> struct A {};
template<class ... Types> struct B {};
using A1_t = A<int, int, float>;
using B1_t = with_tmpl_args_of_t<B, A1_t>;
// test
static_assert(std::is_same_v<B1_t, B<int, int, float>>);
This is limited to class templates that do not use non-type template arguments. There is currently unfortunately no way to define template template parameters which accept both type and non-type template parameters in the same template template parameter's parameter.
Also beware of default arguments. This will not use OtherTmpl
's default arguments, if one of Tmpl
's default arguments matches that position in the template list and will fail if Tmpl
's template list (including defaulted arguments) is larger than OtherTmpl
s.
Regarding the additional examples in your edit:
The second example works directly with the type transform I defined above:
template<typename T>
with_tmpl_args_of_t<B, T> func1()
{
}
The third one can be done like this:
template<typename A, typename... Ts>
with_tmpl_args_of_t<B, A> func2(Ts... args)
{
}
It guarantees that the return type has the same template arguments as A1_t
, but it does accept all types as arguments, even if they don't match the types in the template arguments of A1_t
. This should not usually be a problem. If the types are not convertible to the correct ones you will get an error at the point where you try the conversion.
If you must take the exact same types as in the template arguments of A1_t
for function parameters, you can do something like (untested):
template<typename T>
struct func_with_tmpl_args_of;
template<template<typename...> class Tmpl, typename... Args>
struct func_with_tmpl_args_of<Tmpl<Args...>> {
template<typename F>
struct inner {
constexpr inner(F f) : f(std::move(f)) {}
constexpr static decltype(auto) operator()(Args... args) const {
return f(std::forward<Args>(args)...);
}
private:
F f;
};
};
// example
template<typename T>
constexpr inline auto func2 = func_with_tmpl_args_of<T>::inner{[](auto... args)
-> with_tmpl_args_of_t<B, T> {
// actual function body
}};