Is it possible to create a template template parameter list? - c++

I was wondering whether it's possible to make a list containing template template parameters, like
template <
template <typename...> class TTP0,
template <typename...> class... TTPs
>
struct TTP_List : TTP_List<TTPs...> {};
A problem I encountered is that I did not know a good way to access the elements of the list, that is, TTP0. I would like to use type aliases, typedef or using. I however know this is not possible, because the template template parameters are not types and must therefor not be treated as such.
A approach I could imagine working is making explicit structs to read the data and make it use specializations, such as:
template <template <typename...> class>
struct container_TTPs;
template <template <typename...> class TTP>
struct container_TTPs<std::vector> {};
However, this approach seems very explicit. Is there a way to accomplish this recognition without this use of template specialization?
Feel free to ask if I need to elaborate.
EDIT: For example, I want to be able to use certain expressions for every held type, such as TestClass<TTP_List<std::vector, std::list>>::value, where TestClass uses the std::vector and the std::list, without requiring a variadic template within TestClass, so that multiple TTP_Lists can be passed.

I don't understand what do you mean with "access the elements of the list".
It seems to me that you should give us an example of what do you want, concretely, do accessing elements of the list.
Anyway, as you can use using to "access" (?) typenames
template <typename T0, typename ... Ts>
struct foo
{
using type = T0;
};
you can use a template using to "access" (?) a template-template parameter as follows
template <template <typename...> class T0,
template <typename...> class ... Ts>
struct foo
{
template <typename ... As>
using templ_type = T0<As...>;
};
and you can use it in this way
// vi is a std::vector<int>
foo<std::vector, std::set, std::map>::templ_type<int> vi { 0, 1, 2 };

The problem (a problem) is that a template parameter variadic list (isn't important if of typenames, of values or of template-templates) must be in last position.
So
template <typename ... Ts, typename T0>
struct foo
{ };
is wrong, because Ts... must be in last position, and
template <typename T0, typename ... Ts>
struct foo
{ };
is correct.
With template-template parameters,
template <template <typename ...> class ... Ts,
template <typename ...> class T0>
struct foo
{ };
is wrong where
template <template <typename ...> class T0,
template <typename ...> class ... Ts>
struct foo
{ };
is correct.

Related

Template template class predicate not working in partial specialization

I have many EnableIf traits that basically check whether the input type satisfies an interface. I was trying to create a generic Resolve trait that can be used to transform those into a boolean trait.
Something like this - https://wandbox.org/permlink/ydEMyErOoaOa60Jx
template <
template <typename...> class Predicate,
typename T,
typename = std::void_t<>>
struct Resolve : std::false_type {};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, Predicate<T>> : std::true_type {};
Now if you have an EnableIf trait like so
template <typename T>
using EnableIfHasFoo = std::void_t<decltype(std::declval<T>().foo())>;
You can create a boolean version of that very quickly
template <typename T>
struct HasFoo : Resolve<EnableIfHasFoo, T> {};
Or the analogous variable template.
But for some reason the partial specialization is not working as expected. Resolve does not work as intended. See the output here - https://wandbox.org/permlink/ydEMyErOoaOa60Jx. The same thing implemented "manually" works - https://wandbox.org/permlink/fmcFT3kLSqyiBprm
I am resorting to manually defining the types myself. Is there a detail with partial specializations and template template arguments that I am missing?
I cannot find the exact reason why your example don't work. If you want to dig more into the details of std::void_t, here's an interesting explanation
Even if I cannot explain it in depth, I would like to add another reliable syntax that is used in the detection idiom.
template<
template <typename...> class Predicate,
typename T,
typename = void>
struct Resolve : std::false_type {};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, std::void_t<Predicate<T>>> : std::true_type {};
template <typename T>
using EnableIfHasFoo = decltype(std::declval<T>().foo());
live on compiler explorer
The reason why your approach will fail is that Predicate<T>> in the third template parameter is not a non-deduced context. This causes the deduction to directly fail (see [temp.alias]/2), instead of using the deduced template arguments from elsewhere as in a non-deduced context.
You can wrap your Predicate<T>> to a non-deduced context to make it work:
template<class T>
struct identity {
using type = T;
};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, typename identity<Predicate<T>>::type> : std::true_type {};
Live Demo
Because inside a non-deduced context, the deduction won't happen for Predicate<T> part, instead, it will use the Predicate and T obtained from elsewhere.
As for why the usual detection-idiom (see Guillaume Racicot's answer) will work, it is because std::void_t as a template alias, will be replaced by void in deduction phase (see [temp.alias]/2), thus no deduction will happen.
Here are some examples to illustrate it more clearly:
template<class T>
using always_int = int;
template<template<class> class TT>
struct deductor {};
template<template<class> class TT, class T>
void foo(T, deductor<TT>) {}
template<template<class> class TT, class T>
void bar(T, deductor<TT>, TT<T>) {}
template<class T>
void baz(T, always_int<T>) {}
int main() {
// ok, both T and TT are deduced
foo(0, deductor<always_int>{});
// ERROR, TT<T> is NOT a non-deduced context, deduction failure
bar(0, deductor<always_int>{}, 0);
// ok, T is deduced, always_int<T> is replaced by int so no deduction
baz(0, 0);
}

Why can't we use variadic template at the beginning/middle of template specialization (and how to emulate)?

I was wondering how to emulate the following:
template<class> struct foo;
template<template<class..., int..., class...> class list,
class... clist1, int... ilist1, class... clist2>
struct foo<list<clist1..., ilist1..., clist2...>> {
};
This specialization (hypothetically) accepts a class with any number of classes, then integers, then classes. Currently there seems to be no way to directly implement this. (Bonus points if you can comment on why the standard doesn't support this)
An example of when this would be practical is in Eigen's linear algebra library where most classes are structures like:
Vector<class Scalar_type, int rows, class... options>
Mstrix<class Scalar_type, int rows, int cols, class... options>
With the above enabled, meta-template functions could be used that accept any of these base classes. Because it is not supported you have to write specializations for each class.
Is there any way to emulate a template function that supports accepting classes like the above?
I am looking for a generic solution. (Writing specializations for each class is not generic, and I am not directly looking for a solution to Eigen's library, that is just an example)
Example for clarification
Lets say I want to get the first class of a template class.
Somehow I get the original class type from some other meta-template function. Ergo I don't know what it's template parameters look like.
Maybe it's:
Vector1<class Scalar_type, int rows, class... others>
Or
Vector2<class Scalar_type, class... others>
Because I'm not directly using the type my meta template function must be of something like template<class> struct foo; with various specializations.
In this case getFront is a good example as I would need 2 specializations:
template<class> struct getFront;
template<template<class...,int...,class...> class param,
class... l1, int... l2, class... l3, class first>
struct getFront<param<first, l1..., l2... l3....> {
using type = first; };
and
template<template<class...> class param, class first, class... others>
struct getFront<param<first, others...>> {
using type = first;
};
Is there any way to emulate a template function that supports accepting classes like the above?
What about using template specialization as follows ?
template <typename...>
struct foo;
template <typename ... Ts1, int ... Is, typename ... Ts2>
struct foo<std::tuple<Ts1...>,
std::integer_sequence<int, Is...>,
std::tuple<Ts2...>>
{
};
Or, if you prefer parametrize the template containers, something like
template <template <typename...> class Ct1, typename ... Ts1,
template <int...> class Ci, int ... Is,
template <typename...> class Ct2, typename ... Ts2>
struct foo<Ct1<Ts1...>, Ci<Is...>, Ct2<Ts2...>>
{ };

How to alias a nested template class with variadic parameter packs

Is there any way one can alias a nested template class with a using keyword? Something like this
template <typename... Types>
struct Something {
template <typename... TypesTwo>
struct Another {};
};
template <typename... Types>
template <typename... TypesTwo>
using Something_t = typename Something<Types...>::template Another<TypesTwo...>;
int main() {
Something_t<int><double>{};
return 0;
}
This answer template template alias to a nested template? shows a way to do that but that will no longer work if both the parameter packs are variadic, as the compiler will not know where to start and where to end the type lists.
Not exactly what you asked but... if you can wrap your variadic type lists as arguments of tuples (or similar classes)...
#include <tuple>
template <typename ... Types>
struct Something
{
template <typename ... TypesTwo>
struct Another {};
};
template <typename, typename>
struct variadicWrapper;
template <typename ... Ts1, typename ... Ts2>
struct variadicWrapper<std::tuple<Ts1...>, std::tuple<Ts2...>>
{ using type = typename Something<Ts1...>::template Another<Ts2...>; };
template <typename T1, typename T2>
using Something_t = typename variadicWrapper<T1, T2>::type;
int main()
{
Something_t<std::tuple<int>, std::tuple<double>>{};
}
Not a standalone answer, but an addition to max66's answer:
You could have tried this:
template<typename ... TT, typename ... TTT>
using Alias = typename Something<TT...>::Another<TTT...>;
Looks really nice at first, doesn't it?
Problem then, however will already be with one single template parameter:
Alias<int> a;
Which one is it now? Something<int>::Another<> or Something<>::Another<int>? And if you have more parameters, how to distribute? No chance to get a meaningful solution. So no, you can't do that directly, you have to help yourself with tricks such as max66 proposed...

What can you do with templates with zero template parameters?

I learned some time ago that you can create templates with zero parameters. While it is not possible to create them directly, you can use member templates
template<typename ...T>
struct Maker {
template<T...>
struct HasNParams { };
};
Maker<>::HasNParams<> hnp;
I wonder whether this is intended to be well-formed and what you can do with these beasts. Can you pass them as template arguments, and create explicit specializations (I guess the only scenario is for the empty case then)?
At the risk of sounding obvious, ending recursive instantiation.
template<typename Arg, typename ...T>
struct Maker : public Maker<T...>
{
template<T...>
struct HasNmin1Params { };
};
The point here is that the actual argument list to Maker isn't empty, but we only use N-1 arguments in HasNminOneParams.
Consider the following class template:
template <typename... > struct typelist { };
This is the metaprogramming equivalent of a container. And in the same way that it is useful to have an empty vector or map, it is useful to have an empty typelist. That is, something of type typelist<>. Here are two example use-cases for such a construct.
It could be the termination condition for type recursion:
void foo(typelist<> ) { }
template <typename T, typename... Ts>
void foo(typelist<T, Ts...> ) {
bar<T>();
foo(typelist<Ts...>{});
}
It could be a "return" value for a metafunction, indicating a failure condition.
template <typename F, typename T>
struct filter_one
: std::conditional_t<F::template apply<T>::value,
typelist<T>,
typelist<>>
{ };
Which is a helper we could use to write a typelist filter metafunction:
template <typename F, typename TL>
struct filter;
template <typename F, typename... Ts>
struct filter<F, typelist<Ts...>>
: concat_t<filter_one<F, Ts>...>
{ };
Both of those are very useful features of typelist<>, and that's just the one class template.

Generalized Mixins

I was writing some code where I have a class that can accept mixins as variadic template parameters. However, I also need the mixins to be able to access the base class through the CRTP idiom. Here's a minimal example that cannot quite do what I want:
template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};
However, a mixin that I might pass to Foo will, in general, have several template parameters, like so:
template <class Derived, class Type1, class Type2>
class Bar
{
Derived& operator()()
{
return static_cast<Derived&>(*this);
}
};
How can I change Foo so that I can have it inherit from a number of base classes, where I control the template parameters accepted by each base class? If I hand Foo a list of template-template parameters, along with a list of arguments to pass to them, then I don't see how I would be able to associate each template-template parameter with its arguments. So far, I thought of something like this, but I don't know how I would proceed.
template <template <class...> class T,
template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
I am not quite sure I understood the problem, so please let me rephrase it so that we can start on the right foot.
You need to thread the derived type to the base classes, in a typical CRTP use case, while at the same time passing other template parameter to the various base classes.
That is, a typical base class will be:
template <typename Derived, typename X, typename Y>
struct SomeBase {
};
And you want need to create your type so that you can control the X and Y and at the same time pass the complete Derived class.
I think I would use the apply trick to generate the base class on the fly, from an adapter provided in the argument list of the Derived class.
template <typename Derived, typename X, typename Y>
struct SomeBase {};
template <typename X, typename Y>
struct SomeBaseFactory {
template <typename Derived>
struct apply { typedef SomeBase<Derived, X, Y> type; };
};
// Generic application
template <typename Fac, typename Derived>
struct apply {
typedef typename Fac::template apply<Derived>::type type;
};
Then, you would create the type as:
typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;
Where Foo is defined as:
template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};
And just because it's been a while since I trudged so deeply in templates, I checked it worked.
Of course, the Factory itself is not really a specific to a given type, so we can reuse the wrapper approach you had experimented:
template <template <typename...> class M, typename... Args>
struct Factory {
template <typename Derived>
struct apply { typedef M<Derived, Args...> type; };
};
And yes, it works too.
If I understand your question correctly, you should create template aliases that reduce each mixin to a single template parameter.
template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;
template <typename Derived>
using BazQux = Baz<Derived, Qux>;
typedef Foo<BarIntFloat, BazQux> MyFoo;
Here's a solution I came up with. There may be a more elegant way to do this, but I couldn't think of any. One caveat is that all of the mixins used need to first be nested in the wrapper struct, along with their respective arguments.
template <template <class...> class Mixin, class... Args>
struct wrapper
{
typedef Mixin<Args...> type;
};
template <class... Args>
struct test
{
};
template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{
};
template <class T>
class mixin1 {};
template <class T1, class T2>
class mixin2 {};
template <class T1, class T2, class T3>
class mixin3 {};
int main()
{
test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
return 0;
}
#void-pointer
This is basic omission of variadic templates. User cannot get i-th type from T... or get i-th value from values...
Here is a link from going native 2012 lecture by Andrei Alexandrescu:
template <typename... Ts>
void fun(const Ts&... vs) {}
• Ts is not a type; vs is not a value!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
So Ts/vs should be some kind of tuple.