Reputation: 4849
Consider this:
template <typename Pack, template <typename...> class = std::tuple> struct foo;
template <template <typename...> class P, typename... Ts, template <typename...> class Q>
struct foo<P<Ts...>, Q> {
using type = Q<P<Ts>...>;
};
I've placed the default template in the typedef to be std::tuple
to make this compile, but what I actually want is the default template to be P
, and I don't know of any syntax that allows this. I kept the typedef simple to illustrate the point, which is trying to get P
as the default template. So I came up with the following workaround that seems kind of ugly:
template <typename Pack, template <typename...> class...> struct foo;
template <template <typename...> class P, typename... Ts, template <typename...> class Q>
struct foo<P<Ts...>, Q> {
using type = Q<P<Ts>...>;
};
template <template <typename...> class P, typename... Ts>
struct foo<P<Ts...>> {
using type = P<P<Ts>...>;
};
Is there any better way to do it than this? Perhaps some c++17 syntax that I'm not aware of?
Upvotes: 3
Views: 95
Reputation: 66200
In this case, using
(combined with template
) is your friend.
You need a type-traits to extract the container in Pack
, by example
template <typename>
struct bar;
template <template <typename...> class P, typename ... Ts>
struct bar<P<Ts...>>
{
template <typename ... Us>
using templ_type = P<Us...>;
};
so you can extract the default value, for the second template parameter, from Pack
as follows
template <typename Pack,
template <typename...> class = bar<Pack>::template templ_type>
struct foo;
The following is a full compiling example
#include <type_traits>
template <typename ...>
struct baz
{ };
template <typename>
struct bar;
template <template <typename...> class P, typename ... Ts>
struct bar<P<Ts...>>
{
template <typename ... Us>
using templ_type = P<Us...>;
};
template <typename Pack,
template <typename...> class = bar<Pack>::template templ_type>
struct foo;
template <template <typename...> class P, typename... Ts,
template <typename...> class Q>
struct foo<P<Ts...>, Q>
{ using type = Q<P<Ts>...>; };
int main()
{
foo<baz<short, int, long>> f0;
static_assert( std::is_same<decltype(f0)::type,
baz<baz<short>, baz<int>, baz<long>>>{}, "!" );
}
Upvotes: 2
Reputation: 302708
If you're looking for a different default that's an identity, you can create such a thing:
template <class... I> struct foo_id_impl;
template <template <class...> class P, class... Ts>
struct foo_id_impl<P<Ts>...> { using type = P<P<Ts>...>; };
template <class... Id>
using foo_id = typename foo_id_impl<Id...>::type;
template <class Pack, template <class...> class = foo_id>
struct foo;
I'm not sure that's necessarily better than your solution, but maybe if need this in multiple places.
Upvotes: 1