使用预先编写的包转换更改模板包的一部分
Changing part of a template pack using a pre-written pack transformation
假设你有类似的东西
template <typename, typename, int, typename, int, typename...> struct P
并且您只想反转 typename...
部分。现在您已经编写了通用反向转换:
// 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<>> {};
当然,我们可以用template <typename, typename, int, typename, int, typename...> class P
改写上面的内容,即:
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>> {};
注意到我们只是在重复吗?然后如果我们想做同样的部分逆转事情,我们将不得不对其他模板签名一次又一次地这样做。那么如何通过使用原始 Reverse
本身来避免所有这些重复?
例如,假设我们有
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...>> {};
让我们从 Bar<P<U,V,M,W,N, ArgsReversed...>>
派生 Foo<P<U,V,M,W,N, Args...>>
。如何使用上面定义的 Reverse
来完成此操作?
注意,这与
不同
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>> {};
虽然我怀疑完成它是按照这个思路完成的。当然,倒车只是一个例子。我们希望重用任何转换以仅对(任何)较大模板结构的一部分进行相同的转换。
让我们制作一个类型列表:
template <typename...> struct typelist { };
你可以得到typelist的第N个类型:
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...>>
{ };
您可以反转类型列表:
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<>>
{ };
我们还需要一个index_sequence:
template <size_t...> struct index_sequence;
以及为给定 N:
构建 index_sequence<0, 1, ..., N - 1>
的方法
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;
假设我们有一些可变参数模板 class Foo
:
template <typename ...Ts> struct Foo { };
那么我们可以反推如下:
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)>>
{ };
这里,TL
是Foo
作为typelist的模板参数,RTL
是同一个typelist的反转。要将模板参数提取为包,我们需要创建类似 typelist_get<0, RTL>::type, typelist_get<1, RTL>::type, ..., typelist_get<N - 1, RTL>::type
的内容。这是使用扩展 w.r.t 处的索引序列完成的。 I
完全重现了该模式。
最后我们可以这样使用:
using T = Foo<int, char, double>;
using R = reverse_foo<T>::type;
static_assert(std::is_same<Foo<double, char, int>, R>::value, ":(");
简单的方法是停止使用 int
作为模板的参数。
除此之外,您可以为 class 和 int 类型的特定模式编写元函数,并且 "lift" 模板和实例都约为 classes(其中 int
替换为 integral_constant
),并对它们进行操作(写 "reverse types after N types" 以完成反向操作)。
除此之外,我们可以为您的特定模式手动编码。
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;
其中可能包含语法错误。计划是把它分成 3 个部分。
首先,反转一包(你已经写过了)。
其次,提取 "tail" 参数以从一个实例反转到一个包中。
第三,用另一个包替换"tail"参数。
钩在一起,我们反尾巴。作为 get_tail_t
和 replace_tail_t
的专门化 template
参数的新模式将使 reverse_tail_t
"just work".
假设你有类似的东西
template <typename, typename, int, typename, int, typename...> struct P
并且您只想反转 typename...
部分。现在您已经编写了通用反向转换:
// 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<>> {};
当然,我们可以用template <typename, typename, int, typename, int, typename...> class P
改写上面的内容,即:
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>> {};
注意到我们只是在重复吗?然后如果我们想做同样的部分逆转事情,我们将不得不对其他模板签名一次又一次地这样做。那么如何通过使用原始 Reverse
本身来避免所有这些重复?
例如,假设我们有
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...>> {};
让我们从 Bar<P<U,V,M,W,N, ArgsReversed...>>
派生 Foo<P<U,V,M,W,N, Args...>>
。如何使用上面定义的 Reverse
来完成此操作?
注意,这与
不同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>> {};
虽然我怀疑完成它是按照这个思路完成的。当然,倒车只是一个例子。我们希望重用任何转换以仅对(任何)较大模板结构的一部分进行相同的转换。
让我们制作一个类型列表:
template <typename...> struct typelist { };
你可以得到typelist的第N个类型:
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...>>
{ };
您可以反转类型列表:
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<>>
{ };
我们还需要一个index_sequence:
template <size_t...> struct index_sequence;
以及为给定 N:
构建index_sequence<0, 1, ..., N - 1>
的方法
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;
假设我们有一些可变参数模板 class Foo
:
template <typename ...Ts> struct Foo { };
那么我们可以反推如下:
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)>>
{ };
这里,TL
是Foo
作为typelist的模板参数,RTL
是同一个typelist的反转。要将模板参数提取为包,我们需要创建类似 typelist_get<0, RTL>::type, typelist_get<1, RTL>::type, ..., typelist_get<N - 1, RTL>::type
的内容。这是使用扩展 w.r.t 处的索引序列完成的。 I
完全重现了该模式。
最后我们可以这样使用:
using T = Foo<int, char, double>;
using R = reverse_foo<T>::type;
static_assert(std::is_same<Foo<double, char, int>, R>::value, ":(");
简单的方法是停止使用 int
作为模板的参数。
除此之外,您可以为 class 和 int 类型的特定模式编写元函数,并且 "lift" 模板和实例都约为 classes(其中 int
替换为 integral_constant
),并对它们进行操作(写 "reverse types after N types" 以完成反向操作)。
除此之外,我们可以为您的特定模式手动编码。
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;
其中可能包含语法错误。计划是把它分成 3 个部分。
首先,反转一包(你已经写过了)。
其次,提取 "tail" 参数以从一个实例反转到一个包中。
第三,用另一个包替换"tail"参数。
钩在一起,我们反尾巴。作为 get_tail_t
和 replace_tail_t
的专门化 template
参数的新模式将使 reverse_tail_t
"just work".