Indices trick used for several components - c++

Consider this fully working code:
#include <type_traits>
template <typename T, typename IndexPack> struct Make;
template <typename T, template <T...> class P, T... Indices>
struct Make<T, P<Indices...>> {
using type = P<(Indices+1)..., (-3*Indices)..., (Indices-1)...>;
};
template <int...> class Pack;
int main() {
static_assert (std::is_same<Make<int, Pack<1,2,3,4>>::type,
Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>>::value, "false");
}
What I actually want the output to be is
Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3>
instead of Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>. I first tried
using type = P<(Indices+1, -3*Indices, Indices-1)...>;
but that is simply understood by the compiler to be a useless comma operator. What is the desired syntax to get what I want? If there is no such syntax, what is the cleanest way to do this, keeping in mind that using Indices 3 times is just an example (we may want to use it more than 3 times). Please don't tell me that I have to write a helper to extract the individual packs and then "interlace" all the elements. That nightmarish method cannot be the best solution (and such a solution would also only work if we knew exactly how many individual packs to extract).
Would defining
template <typename T, template <T...> class P, T I>
struct Component {
using type = P<I+1, -3*I, I-1>;
};
help somehow? Make a pack expansion on this?

Yes, you can concat recursively:
template <typename, typename, typename> struct Concat;
template <typename T, template <T...> class P, T... A, T... B>
struct Concat<T, P<A...>, P<B...>> {
using type = P<A..., B...>;
};
template <typename T, typename IndexPack> struct Make;
template <typename T, template <T...> class P, T... I, T F >
struct Make<T, P<F, I...>> {
using type = typename Concat<T,
typename Make<T, P<F>>::type,
typename Make<T, P<I...>>::type>::type;
};
template <typename T, template <T...> class P, T I>
struct Make<T, P<I>> {
using type = P<I+1, -3*I, I-1>;
};
Demo

This was inspired by Columbo's solution. It uses the pack expansion syntax that I originally sought, namely
using type = typename Merge<T, typename Component<T, P, Indices>::type...>::type;
As a result, now Make is reusable, first using Triple, and then using Quadruple, so any number of usages of Indices can be expanded simultaneously. Here Component is a template-template-template parameter passed into Make:
#include <type_traits>
template <typename T, typename... Packs> struct Merge;
template <typename T, template <T...> class P1, template <T...> class P2, T... Is, T... Js>
struct Merge<T, P1<Is...>, P2<Js...>> {
using type = P1<Is..., Js...>;
};
template <typename T, typename Pack1, typename Pack2, typename... Packs>
struct Merge<T, Pack1, Pack2, Packs...> {
using type = typename Merge<T, Pack1, typename Merge<T, Pack2, Packs...>::type>::type;
};
template <typename T, template <T...> class P, T I>
struct Triple {
using type = P<I+1, -3*I, I-1>;
};
template <typename T, template <T...> class P, T I>
struct Quadruple {
using type = P<I+1, -3*I, I-1, I>;
};
template <typename T, typename IndexPack,
template <typename U, template <U...> class P, U I> class Component> struct Make;
template <typename T, template <T...> class Z, T... Indices,
template <typename U, template <U...> class P, U I> class Component>
struct Make<T, Z<Indices...>, Component> {
using type = typename Merge<T, typename Component<T, Z, Indices>::type...>::type;
};
template <int...> class Pack;
int main() {
static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Triple>::type,
Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3>>::value, "false");
static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Quadruple>::type,
Pack<2,-3,0,1, 3,-6,1,2, 4,-9,2,3, 5,-12,3,4>>::value, "false");
}

Related

Cascade variadic template template parameters

How can I cascade variadic types? I.e.:
template <typename... T>
using Cascade = ???; // T1<T2<T3<...>>>
Example:
using Vector2D = Cascade<std::vector, std::vector, double>;
static_assert(std::is_same_v<Vector2D, std::vector<std::vector<double>>>);
You cannot have CascadeRight. T1 is not a typename, it is a template, and so are most of the others, but the last one is a typename. You cannot have different parameter kinds (both types and templates) in the same parameter pack. You also cannot have anything after a parameter pack.
You can have CascadeLeft like this:
template <typename K, template <typename...> class ... T>
class CascadeLeft;
template <typename K>
class CascadeLeft<K>
{
using type = K;
};
template <typename K,
template <typename...> class T0,
template <typename...> class... T>
class CascadeLeft<K, T0, T...>
{
using type = typename CascadeLeft<T0<K>, T...>::type;
};
Frankly, std::vector<std::vector<double>> is much more transparent than CascadeLeft<double, std::vector, std::vector>, so I wouldn't bother.
Expanding on the accepted answer with CascadeRight and support for multiple types for the innermost template:
template<template<typename...> typename Head, template<typename...> typename... Tail>
struct CascadeRight {
template<typename... T>
using type = Head<typename CascadeRight<Tail...>::type<T...>>;
};
template<template<typename...> typename Head>
struct CascadeRight<Head> {
template<typename... T>
using type = Head<T...>;
};
template<template<typename...> typename Head, template<typename...> typename... Tail>
struct CascadeLeft {
template<typename... T>
using type = typename CascadeLeft<Tail...>::type<Head<T...>>;
};
template<template<typename...> typename Head>
struct CascadeLeft<Head> {
template<typename... T>
using type = Head<T...>;
};
using T1 = CascadeRight<std::vector, std::map>::type<int, double>;
using T2 = CascadeLeft<std::map, std::vector>::type<int, double>;

Expanding with pack of templates

Define template_pack as in the following example. Given
template <typename> struct A;
template <typename, typename, typename> struct B;
template <typename, typename> struct C;
then
template_pack<std::tuple<char, bool, double>, A, B, C>::type
is to be
std::tuple<A<char>, B<char, bool, double>, C<char, bool>>
i.e. always reading from left to right in the tuple, so as to get enough types to fit each template.
Here's my solution so far. But it only works for templates that take up to 3 types, and I don't see how I can generalize to templates of any number of types:
#include <type_traits>
#include <tuple>
template <template <typename...> class Template, typename... Ts> struct use_template;
template <template <typename> class Template, typename A, typename... Rest>
struct use_template<Template, A, Rest...> {
using type = Template<A>;
};
template <template <typename, typename> class Template, typename A, typename B, typename... Rest>
struct use_template<Template, A, B, Rest...> {
using type = Template<A,B>;
};
template <template <typename, typename, typename> class Template, typename A, typename B, typename C, typename... Rest>
struct use_template<Template, A, B, C, Rest...> {
using type = Template<A,B,C>;
};
template <typename Pack, template <typename...> class... Templates> struct template_pack;
template <template <typename...> class P, typename... Ts, template <typename...> class... Templates>
struct template_pack<P<Ts...>, Templates...> {
using type = P<typename use_template<Templates, Ts...>::type...>;
};
// Testing
template <typename> struct A;
template <typename, typename, typename> struct B;
template <typename, typename> struct C;
int main() {
static_assert (std::is_same<
template_pack<std::tuple<char, bool, double>, A, B, C>::type,
std::tuple<A<char>, B<char, bool, double>, C<char, bool>>
>::value, "");
}
How to generalize the above? Is it even possible?
This is "find shortest prefix".
Utilities:
// pack that is easy to append to
template<class... Ts>
struct pack{
template<class... T1s>
using append = pack<Ts..., T1s...>;
};
template<class...> using void_t = void;
The meat:
// find the shortest proper prefix Ts... of [T, Rest...]
// such that A<Ts...> is well-formed, and return it.
template<template<class...> class A, // template we are going to look at
class AlwaysVoid, // for void_t
class Current, // pack containing the types we are testing next
class T, // next type to add to pack if test fails
class... Rest> // remaining types
struct find_viable
: find_viable<A, AlwaysVoid, typename Current::template append<T>, Rest...> {};
// picked if A<Ts...> is well-formed
template<template<class...> class A, class... Ts, class T, class...Rest>
struct find_viable<A, void_t<A<Ts...>>, pack<Ts...>, T, Rest...> {
using type = A<Ts...>;
};
// Finds the shortest prefix of Ts... such that A<prefix...> is well formed.
// the extra void at the end is slightly hackish - find_viable only checks
// proper prefixes, so we add an extra dummy type at the end.
template<template<class...> class A, class... Ts>
using find_viable_t = typename find_viable<A, void, pack<>, Ts..., void>::type;
Then use it:
template <typename Pack, template <typename...> class... Templates> struct template_pack;
template <template <typename...> class P, typename... Ts,
template <typename...> class... Templates>
struct template_pack<P<Ts...>, Templates...> {
using type = P<find_viable_t<Templates, Ts...>...>;
};
I won't write it all, but I'll do a walkthrough.
template<template<class...>class Z>
struct z_template{
template<class...Ts>using result=Z<Ts...>;
};
this lets you manipulate templates like types.
template<template<class...>class Z, class...Ts>
using can_apply = /* ... */;
this asks the question "is Z<Ts...> valid? If so, return true_type".
template<class...>struct types{using type=types;};
this is a light-weight template pack.
template<template<class...>class Z, class types>
using apply = /* ... */;
this takes a template Z, and a types<Ts...>, and returns Z<Ts...>.
template<class Z, class types>
using z_apply = apply<typename Z::template result, types>;
this does it with a z_template argument instead of a template one.
Working on types as often as possible makes many kinds of metaprogramming easier.
Next we write
template<class types>using pop_front = // ...
template<class types>using reverse = // ...
template<class types>using pop_back = reverse<pop_front<reverse<types>>>;
which remove elements from the front and back of types.
template<class Result>
struct z_constant {
template<class...Ts>using result=Result;
};
This finds the longest prefix of types that can be passed to Z::template result<???> validly. Some work to avoid passing too-short sequences is done, in case they fail "late":
template<class Z, class types>
struct z_find_longest_prefix :
std::conditional_t<
can_apply< z_apply, Z, types >{},
z_constant<types>,
z_template<longest_prefix>
>::template result<Z, pop_back<types>>
{};
template<class Z, class types>
using z_find_longest_prefix_t = typename z_find_longest_prefix<Z,types>::type;
struct empty_t {};
template<class Z>
struct z_find_longest_prefix<Z,types<>>:
std::conditional_t<
can_apply< Z::template result >,
types<>,
empty_t
>
{};
find_longest_prefix will fail to compile if there is no valid prefix.
template<class Z, class types>
using z_apply_longest_prefix_t =
z_apply< Z, z_find_longest_prefix_t<Z, types> >;
template<class src, template<class...>class... Zs>
struct use_template;
template<class src, template<class...>class... Zs>
using use_template_t = typename use_template<src, Zs...>::type;
template<template<class...>class Z0, class...Ts, template<class...>class... Zs>
struct use_template< Z0<Ts...>, Zs... > {
using type=Z0<
z_apply_longest_prefix_t<
z_template<Zs>, types<Ts...>
>...
>;
};
and up to typos and similar problems, done.
Can be cleaned up lots. Probably the entire z_ subsystem isn't needed. I just tend to run towards it whenever doing serious metaprogramming, because suddenly any metafunction I write that applies to types now can be used on templates.
reverse takes a bit of work to do efficiently.
can_apply is available in many of my posts.
pop_front is trivial.
apply should be easy.
This looked fun so I tried my hand at it; I'm not claiming this is in any way better than the existing answers, but maybe some people will find it clearer:
namespace detail {
template<typename...>
using void_t = void;
template<template<typename...> class, typename, typename, typename EnableT = void>
struct fill_template;
template<template<typename...> class TemplateT, typename TupleT, std::size_t... Is>
struct fill_template<
TemplateT, TupleT, std::index_sequence<Is...>,
void_t<TemplateT<std::tuple_element_t<Is, TupleT>...>>
>
{
using type = TemplateT<std::tuple_element_t<Is, TupleT>...>;
};
template<
template<typename...> class TemplateT, typename TupleT,
std::size_t I, std::size_t N
>
struct fill_template_dispatcher
{
template<typename T, typename = typename T::type>
static constexpr std::true_type test(int) { return {}; }
template<typename T>
static constexpr std::false_type test(long) { return {}; }
using candidate_t = fill_template<TemplateT, TupleT, std::make_index_sequence<I>>;
using type = typename std::conditional_t<
test<candidate_t>(0),
candidate_t,
fill_template_dispatcher<TemplateT, TupleT, I + 1, I != N ? N : 0>
>::type;
};
template<template<typename...> class TemplateT, typename TupleT, std::size_t I>
struct fill_template_dispatcher<TemplateT, TupleT, I, 0>
{
static_assert(I != I, "tuple contains insufficient types to satisfy all templates");
};
} // namespace detail
template<typename TupleT, template<typename...> class... TemplateTs>
struct template_pack
{
static_assert(std::tuple_size<TupleT>::value, "tuple must not be empty");
using type = std::tuple<typename detail::fill_template_dispatcher<
TemplateTs, TupleT, 0, std::tuple_size<TupleT>::value
>::type...>;
};
template<typename TupleT, template<typename...> class... TemplateTs>
using template_pack_t = typename template_pack<TupleT, TemplateTs...>::type;
Online Demo
Note that for variadic class templates this will pass as few types as possible (see D in the test); for an implementation that passes as many types as possible instead, see that variation of the code here (only two lines are changed in the implementation).

Is this template syntax illegal?

I'm getting an "internal compiler error" with this using GCC 4.9.2:
#include <type_traits>
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
template <typename T, template <T...> class Z, T N, T... Is,
template <typename U, U, U> class Comparator>
struct Sort<T, Z<N, Is...>, 0, Comparator> {
template <T I>
struct less_than : std::integral_constant<bool, Comparator<T, I, N>::value> {
};
};
int main() {}
The error message states:
c:\ADandD>g++ -std=c++14 ComparatorAndSorterTGeneralized.cpp
ComparatorAndSorterTGeneralized.cpp:254:80: internal compiler error: in tsubst,
at cp/pt.c:11738
template<T I>
struct less_than : std::integral_constant<bool, Comparator<T,I,N>::value> {};
^
Please submit a full bug report,
with preprocessed source if appropriate.
See http://gcc.gnu.org/bugs.html for instructions.
The issue is the template <typename U, U, U> class Comparator being used. I've never tried this before. At first I tried the template <typename T, T, T> class Comparator, but that would not compile because of the template shadowing, so I knew that was illegal. And then changing it to U still did not compile, so I thought the whole idea is not allowed.
Update: Upon instantiating, this compiles in Visual Studio 2015 Preview:
#include <type_traits>
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
template <typename T, template <T...> class Z, T N, T... Is,
template <typename U, U, U> class Comparator>
struct Sort<T, Z<N, Is...>, 0, Comparator> {
template <T I>
struct less_than : std::integral_constant<bool, Comparator<T, I, N>::value> {
};
};
template <int...>
struct index_sequence {};
template <typename T, T A, T B>
struct LessThan : std::integral_constant < bool,
A<B> {};
enum { QuickSort, MergeSort, InsertionSort };
int main() {
Sort<int, index_sequence<4, 5, 6, 1, 2, 7>, QuickSort, LessThan> quickSort;
}
template <typename T, typename, int, template <typename U, U, U> class>
struct Sort;
This is perfectly legal.
It could be redeclared like this, giving names to all the parameters:
template <typename T, typename T2, int I, template <typename U, U X, U Y> class TT>
struct Sort;
It declares a class template Sort which has four template parameters, the type parameter T, a second type parameter T2 (unnamed in the original), a non-type template parameter I, and a template template parameter TT.
The template template parameter TT must a class template taking three template parameters, U is a type parameter and the second and third (X and Y) are non-type template parameters of type U.
A suitable argument for the fourth template parameter of Sort might be something like:
template <typename T, T t1, T t2>
class Foo
{ static const bool value = t1 < t2; };
which would be instantiated like:
Foo<int, 1, 2> fi;
or
Foo<char, 'a', 'b'> fc;

Changing part of a template pack using a pre-written pack transformation

Suppose you have something like
template <typename, typename, int, typename, int, typename...> struct P
and you want to reverse the typename... part only. Now you've already written the generic reverse transformation:
// Reverse<Pack<Types...>>::type is Pack<Types'...>, where Types'... is Types... reversed.
template <typename, typename> struct ReverseHelper;
template <template <typename...> class P, typename Pack>
struct ReverseHelper<P<>, Pack> {
using type = Pack;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Types>
struct ReverseHelper<P<First, Rest...>, P<Types...>> : ReverseHelper<P<Rest...>, P<First, Types...>> {};
template <typename> struct Reverse;
template <template <typename...> class P, typename... Types>
struct Reverse<P<Types...>> : ReverseHelper<P<Types...>, P<>> {};
Of course, we could rewrite the above with template <typename, typename, int, typename, int, typename...> class P instead, namely:
template <typename, typename> struct ReverseHelper1;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename Pack>
struct ReverseHelper1<P<U,V,M,W,N>, Pack> {
using type = Pack;
};
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename First, typename... Rest, typename... Types>
struct ReverseHelper1<P<U,V,M,W,N, First, Rest...>, P<Types...>> : ReverseHelper<P<U,V,M,W,N, Rest...>, P<First, Types...>> {};
template <typename> struct Reverse1;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename... Types>
struct Reverse1<P<U,V,M,W,N, Types...>> : ReverseHelper1<P<U,V,M,W,N, Types...>, P<U,V,M,W,N>> {};
Notice we are just repeating? And then we would have to do this again and again for other template signatures if we want to do the same partial reversal thing. So how to make the approach by using the original Reverse itself to avoid all this repetition?
For example, let's suppose we have
template <typename> struct Foo;
template <typename> struct Bar;
template <template <typename, typename, int, typename, int, typename...> class P,
typename U, typename V, int M, typename W, int N, typename... Args>
struct Foo<P<U,V,M,W,N, Args...>> {};
Let's have Foo<P<U,V,M,W,N, Args...>> derive from Bar<P<U,V,M,W,N, ArgsReversed...>>. How to accomplish this using the defined Reverse from above?
Note, it's not the same thing as
template <template <typename, typename, int, typename, int, typename> class P,
typename U, typename V, int M, typename W, int N,
template <typename...> class Q, typename... Args>
struct Foo<P<U,V,M,W,N, Q<Args...>>> : Bar<P<U,V,M,W,N, typename Reverse<Q<Args...>>::type>> {};
though I suspect accomplishing it is done something along the lines of this. Of course, reversing is just an example. We want to reuse any transformation to make the same transformation for only part of (any) larger template structure.
The easy way is to stop using int as arguments to templates.
Barring that, you can write metafunctions for a particular pattern of class and int types, and "lift" both the template and the instance to being about classes (where int is replaced with integral_constant), and operate on those (write "reverse types after N types" to get the reverse done).
Barring that, we can hand code for your particular pattern.
template<class...>struct types{using type=types;};
namespace details {
template<class T, class types>
struct replace_tail;
template<class T, class types>
using replace_tail_t = typename replace_tail<T,types>::type;
template<class T>
struct get_tail;
template<class T>
using get_tail_t = typename get_tail<T,types>::type;
template<template <class, class, int, class, int, class...> class P,
class A, class B, int C, class D, int E, class...Fs,
class... Ts
>
struct replace_tail<P<A,B,C,D,E,Fs...>,types<Ts...>> {
using type = P<A,B,C,D,E,Ts...>;
};
template<template <class, class, int, class, int, class...> class P,
class A, class B, int C, class D, int E, class...Fs
>
struct get_tail<P<A,B,C,D,E,Fs...>>:types<Fs...>{};
template<class T>
using reverse_t = ReverseHelper<T>::type;
template<class T>
using reverse_tail = replace_tail_t < T, reverse_t<get_tail_t<T>> >;
}
using details::reverse_tail;
which may contain syntax errors. The plan is to break it into 3 parts.
First, reversing a pack (you wrote this already).
Second, extracting the "tail" arguments to reverse from an instance into a pack.
Third, replacing the "tail" arguments with another pack.
Hooked together, we reverse the tail. As a specializing get_tail_t and replace_tail_t for a new pattern of template arguments will make reverse_tail_t "just work".
Let's make a typelist:
template <typename...> struct typelist { };
You can get the N-th type of the typelist:
template <size_t N, typename> struct typelist_get;
template <typename T, typename ...Ts>
struct typelist_get<0, typelist<T, Ts...>>
{
using type = T;
};
template <size_t N, typename T, typename ...Ts>
struct typelist_get<N, typelist<T, Ts...>>
: typelist_get<N - 1, typelist<Ts...>>
{ };
You can reverse a typelist:
template <typename, typename> struct reverse_helper;
template <typename T, typename ...Ts, typename ...Rs>
struct reverse_helper<typelist<T, Ts...>, typelist<Rs...>>
: reverse_helper<typelist<Ts...>, typelist<T, Rs...>>
{ };
template <typename ...Rs>
struct reverse_helper<typelist<>, typelist<Rs...>>
{
using type = typelist<Rs...>;
};
template <typename T> struct typelist_reverse
: reverse_helper<T, typelist<>>
{ };
We also need a index_sequence:
template <size_t...> struct index_sequence;
and a way to build an index_sequence<0, 1, ..., N - 1> for given N:
template <std::size_t N, std::size_t ...I>
struct index_sequence_builder
{
using type = typename index_sequence_builder<N - 1, N - 1, I...>::type;
};
template <std::size_t ... I>
struct index_sequence_builder<0, I...>
{
using type = index_sequence<I...>;
};
template <std::size_t N>
using make_index_sequence = typename index_sequence_builder<N>::type;
Let's say we have some variadic template class Foo:
template <typename ...Ts> struct Foo { };
Then we can reverse it as follows:
template <typename, typename> struct reverse_foo_impl;
template <typename ...Ts, size_t ...I>
struct reverse_foo_impl<Foo<Ts...>, index_sequence<I...>>
{
using TL = typelist<Ts...>;
using RTL = typename typelist_reverse<TL>::type;
using type = Foo<typename typelist_get<I, RTL>::type...>;
};
template <typename> struct reverse_foo;
template <typename...Ts>
struct reverse_foo<Foo<Ts...>>
: reverse_foo_impl<Foo<Ts...>, make_index_sequence<sizeof...(Ts)>>
{ };
Here, TL are the template parameters of Foo as typelist, RTL is the same typelist reversed. To extract the template parameters as pack, we need to create something like typelist_get<0, RTL>::type, typelist_get<1, RTL>::type, ..., typelist_get<N - 1, RTL>::type. This is accomplished using the index sequence where the expansion w.r.t. I exactly recreates that pattern.
In the end we can use it like this:
using T = Foo<int, char, double>;
using R = reverse_foo<T>::type;
static_assert(std::is_same<Foo<double, char, int>, R>::value, ":(");

How do I get the index of a type matching some predicate?

I have a variadic list of types and I want to find the index of the first type that has a base of type Base. If it cannot find this, it should return -1. This is how I would like to do it:
typedef std::tuple<A, B, C> Tuple;
int idx = find_if<std::is_base_of, Base, Tuple>::value;
Where std::is_base_of is the predicate, Base is its argument and the tuple are the elements to check.
What about
constexpr std::size_t npos = -1;
template <template <class T> class, typename, std::size_t pos = 0>
struct find_if;
template <template <class T> class Pred, typename T, std::size_t pos, typename... tail>
struct find_if<Pred, std::tuple<T, tail...>, pos> :
std::conditional<Pred<T>::value,
std::integral_constant<std::size_t, pos>,
find_if<Pred, std::tuple<tail...>, pos+1>>::type {};
template <template <class T> class Pred>
struct find_if<Pred, std::tuple<>> : std::integral_constant<std::size_t, npos> {};
template <template <class, class> class T, class U>
struct bind
{
template <class X>
using first = T<U, X>;
template <class X>
using second = T<X, U>;
};
Use like this:
find_if<bind<std::is_base_of, Base>::first, Tuple>::value
Demo.