Как то так? Использование преобразования типа на основе частичной специализации:
#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>>);
Это ограничено шаблонами классов, которые не используют нетиповые аргументы шаблона. К сожалению, в настоящее время нет способа определить параметры шаблона шаблона, которые принимают как типовые, так и нетиповые параметры шаблона в одном и том же параметре шаблона шаблона.
Также остерегайтесь аргументов по умолчанию. Это не будет использовать аргументы OtherTmpl
по умолчанию, если один из аргументов Tmpl
по умолчанию соответствует этой позиции в списке шаблонов, и потерпит неудачу, если список шаблонов Tmpl
(включая аргументы по умолчанию) больше OtherTmpl
s.
Что касается дополнительных примеров в вашем редактировании:
Второй пример работает непосредственно с преобразованием типа, которое я определил выше:
template<typename T>
with_tmpl_args_of_t<B, T> func1()
{
}
Третий это можно сделать так:
template<typename A, typename... Ts>
with_tmpl_args_of_t<B, A> func2(Ts... args)
{
}
Это гарантирует, что возвращаемый тип имеет те же аргументы шаблона, что и A1_t
, но он принимает все типы в качестве аргументов, даже если они не соответствуют типам в аргументах шаблона A1_t
. Это обычно не должно быть проблемой. Если типы не могут быть преобразованы в правильные, вы получите ошибку в том месте, где вы пытаетесь выполнить преобразование.
Если вы должны принять те же типы, что и в аргументах шаблона A1_t
для параметров функции вы можете сделать что-то вроде (не проверено):
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
}};