可变参数模板:交错多个包
Variadic templates: Interlacing multiple packs
给定任意数量的包,从每个包中取出第一种类型,将它们放在一起。 然后每个包中的第二种类型,将它们放在一起,等等......然后将它们全部合并。 任何左派都会在他们之间重复这个过程。 例如,使用整数表示不同的类型以获得更好的可读性,
InterlacePacks<Pack<1 2 3 4>, Pack<5 6 7>, Pack<8 9 10 11 12>>::type
会给
Pack<1 5 8 2 6 9 3 7 10 4 11 12>
如果所有包的大小相同,则以下代码有效。 当包装大小不同时,我现在完全无法处理"剩菜"。 这是我到目前为止的代码。 我解释每个阶段,以便您知道我的计划是什么:
#include <iostream>
// First a helper to remove the first N types from a pack:
template <int, typename> struct RemoveHead;
template <typename Pack>
struct RemoveHead<0, Pack> { using type = Pack; };
template <template <typename...> class P, typename First, typename... Rest>
struct RemoveHead<0, P<First, Rest...>> { using type = P<First, Rest...>; };
template <int N, template <typename...> class P, typename First, typename... Rest>
struct RemoveHead<N, P<First, Rest...>> : RemoveHead<N-1, P<Rest...>> {};
// Now a helper to merge multiple packs:
template <typename...> struct MergePacks;
template <typename Pack>
struct MergePacks<Pack> {
using type = Pack;
};
// Final Pack type shall be the first one listed, if there are different pack types.
template <template <typename...> class P1, template <typename...> class P2, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P1<Types1...>, P2<Types2...>, Packs...> : MergePacks<P1<Types1..., Types2...>, Packs...> {};
// First collect the first type from each pack:
template <typename, typename...> struct InterlacePacksHelper1;
template <template <typename...> class P, typename... Ts>
struct InterlacePacksHelper1<P<Ts...>> { using type = P<Ts...>; };
template <template <typename...> class P, template <typename...> class FirstPack, typename... Ts, typename First, typename... Rest, typename... Packs>
struct InterlacePacksHelper1<P<Ts...>, FirstPack<First, Rest...>, Packs...> : InterlacePacksHelper1<P<Ts..., First>, Packs...> {};
// Now remove the first type from each pack and repeat the process. Use a parameter N as a counter, where N will start as the minimum size of the packs.
template <int, typename, typename...> struct InterlacePacksHelper;
template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacksHelper<0, P<Ts...>, Packs...> { using type = P<Ts...>; };
template <int N, template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacksHelper<N, P<Ts...>, Packs...> : InterlacePacksHelper<N-1,
typename MergePacks<P<Ts...>, typename InterlacePacksHelper1<P<>, Packs...>::type>::type,
typename RemoveHead<1, Packs>::type...> {};
// Now obtain the smallest pack size, given a list of packs.
template <int N, typename...> struct MinPackSize;
template <int N>
struct MinPackSize<N> : std::integral_constant<int, N> {};
template <int N, template <typename...> class P, typename... Types, typename... Packs>
struct MinPackSize<N, P<Types...>, Packs...> : std::integral_constant<int,
(sizeof...(Types) < N) ? sizeof...(Types) : N> {};
// Finally, InterlacePacks itself.
template <typename...> struct InterlacePacks;
template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacks<P<Ts...>, Packs...> : InterlacePacksHelper<MinPackSize<sizeof...(Ts), Packs...>::value, P<>, P<Ts...>, Packs...> {};
// test ----------------------------------------------------------------
template <typename...> struct Pack {};
template <typename...> struct Group {};
template <typename...> struct Wrap {};
struct Object {}; struct Blob {};
int main() {
using TestPack1 = Pack<int, double, Object>; // 3 types
using TestPack2 = Group<double, std::string, int, short, long>; // 5 types
using TestPack3 = Wrap<char, short, Blob, std::string>; // 4 types
InterlacePacks<TestPack1, TestPack2, TestPack3>::type interlacedPack;
std::cout << std::boolalpha << std::is_same< decltype(interlacedPack),
Pack<int, double, char, double, std::string, short, Object, int, Blob> >::value << std::endl; // true
// Want it to be Pack<int, double, char, double, std::string, short, Object, int, Blob, short, std::string, long>
}
那么如何修复代码以使所需的输出
Pack<int, double, char, double, std::string, short, Object, int, Blob, short, std::string, long>
结果反而?
注意:我尝试使用MaxPackSize
MinPackSize
的intead,正如预期的那样,这不会编译。 一个想法是在MinPackSize
迭代后丢弃空包并继续该过程,直到MaxPackSize
迭代完成(每次都删除新的空包)。不过这是理论上的(还没有尝试过):
template <typename, typename...> struct RemoveAllEmptyPacksHelper;
template <template <typename...> class P, typename... Packs>
struct RemoveAllEmptyPacksHelper<P<Packs...>> : Identity<P<Packs...>> {};
template <template <typename...> class P, typename... CurrentPacks, template <typename...> class FirstPack, typename... Types, typename... Packs>
struct RemoveAllEmptyPacksHelper<P<CurrentPacks...>, FirstPack<Types...>, Packs...> :
std::conditional<(sizeof...(Types) == 0),
RemoveAllEmptyPacksHelper<P<CurrentPacks...>, Packs...>,
RemoveAllEmptyPacksHelper<P<CurrentPacks..., FirstPack<Types...>>, Packs...>
>::type {};
template <typename> struct RemoveAllEmptyPacks;
template <template <typename...> class P, typename... Packs>
struct RemoveAllEmptyPacks<P<Packs...>> : RemoveAllEmptyPacksHelper<P<>, Packs...> {};
这是我
迄今为止最短的C++11次尝试:
template <class T, class...> struct interlace_ {using type = T;};
template <class... R, template<class...> class T, class f, class... t, class... P>
struct interlace_<std::tuple<R...>, T<f, t...>, P...>
: interlace_<std::tuple<R..., f>, P..., T<t...>> {};
template <class... R, template<class...> class T, class f, class... P>
struct interlace_<std::tuple<R...>, T<f>, P...>
: interlace_<std::tuple<R..., f>, P...> {};
template <class... packs>
using interlace = interlace_<std::tuple<>, packs...>;
演示。 P
代表包,R
是(当前)结果包,f
是第一种类型,t
是当前观察到的包的尾部。 T
是保存包的模板。
以下内容
可能会有所帮助,它使用帮助程序类并在第一个模板参数中聚合结果:
template <typename...> struct InterlacePacksHelper;
// general case: take first parameter and en-queue the Pack for further computation
template <template <typename...> class PRes, typename... Ts,
template <typename...> class P, typename U, typename... Us,
typename... Packs>
struct InterlacePacksHelper<PRes<Ts...>, P<U, Us...>, Packs...>
{
using type = typename InterlacePacksHelper<PRes<Ts..., U>, Packs..., P<Us...>>::type;
};
// final case
template <template <typename...> class PRes, typename... Ts>
struct InterlacePacksHelper<PRes<Ts...>>
{
using type = PRes<Ts...>;
};
// Remove empty Pack.
template <template <typename...> class PRes, typename... Ts,
template <typename...> class P,
typename... Packs>
struct InterlacePacksHelper<PRes<Ts...>, P<>, Packs...>
{
using type = typename InterlacePacksHelper<PRes<Ts...>, Packs...>::type;
};
// Finally, InterlacePacks itself.
template <typename...> struct InterlacePacks;
template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacks<P<Ts...>, Packs...> : InterlacePacksHelper<P<>, P<Ts...>, Packs...>::type
{
using type = typename InterlacePacksHelper<P<>, P<Ts...>, Packs...>::type;
};
现场演示
相关文章:
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 从变长参数列表中提取std::string