There's a shortcut you can take if each template has only one argument:
template <template<class> class... Templates, class... Types>
template_pack(const Templates<Types>&...) -> template_pack<Templates...>;
With only one argument each, it's easy to split up one pack amongst all the templates.
Unfortunately, I don't know of any way to have a separate pack per template without knowing the number of templates in advance. Therefore, a layer of indirection through a helper seems required. In addition, deduction guides must be of the form -> template_pack<something>
, presumably to avoid having the compiler do too much work or run into impossible problems. Given this, the class needs a slight tweak:
template <template <class...> class... Templates>
class holder {};
// Class definition
template<class Holder>
class template_pack;
template <template <class...> class... Templates>
class template_pack<holder<Templates...>>
{
public:
template <class... Types>
constexpr template_pack(const Types&...) noexcept {}
};
With this tweak, we can make a helper (that could probably be simplified to be a bit more straightforward):
template<template<class...> class... TTs>
struct result {
using type = holder<TTs...>;
};
template<class T>
struct type {};
template<class Prev, class Current, class... Rest>
auto helper() {
return []<template<class...> class... PrevTTs, template<class...> class CurrTT, class... CurrTs>(result<PrevTTs...>, type<CurrTT<CurrTs...>>) {
if constexpr (sizeof...(Rest) == 0) {
return result<PrevTTs..., CurrTT>{};
} else {
return helper<result<PrevTTs..., CurrTT>, Rest...>();
}
}(Prev{}, type<Current>{});
}
I use C++20's templated lambdas to pull apart two templates from their arg packs inline instead of having an additional helper layer, but that additional layer is still possible in earlier standards, just uglier. The helper recursively takes a previous result, pulls apart one template at a time, adds it to the result, and recursively calls itself until there are no arguments left.
With this helper, it becomes possible to make the deduction guide:
// Class template argument deduction guide
template <typename... Ts>
template_pack(const Ts&...) -> template_pack<typename decltype(helper<result<>, Ts...>())::type>;
You can find a full example here. It might also be possible to improve this code somewhat significantly, but the core idea is there.