gpt4 book ai didi

c++ - 如何使用 Variadic 模板来展平类型树?

转载 作者:可可西里 更新时间:2023-11-01 16:40:47 27 4
gpt4 key购买 nike

我有这样的构造:

template<typename... Ts>
struct List {}

typedef List<char,List<int,float,List<int,unsigned char>>,List<unsigned,short>> MyList;

我想基本上将其扁平化为一个列表。什么是最好的方法?我想我可以用递归做一些事情,如果我摆弄它足够长的时间,但有些东西告诉我应该有更好的方法。

我想要的结果应该与上面的树类似:

typedef List<char,int,float,int,unsigned char,unsigned,short> FlattenedList;

这是我的第一次尝试:

template<typename... Ts>
struct List{};

template<typename... Ts>
struct FlattenTree{
typedef List<Ts...> Type;
};
template<typename... Ts, typename... Us, typename... Vs>
struct FlattenTree<Ts...,List<Us...>,Vs...>{
typedef typename FlattenTree<Ts..., Us..., Vs...>::Type Type;
};

但它会导致此错误:error C3515: if an argument for a class template partial specialization is a pack expansion it shall be the last argument

rici指出here MSVC2013 提示什么,所以这里没有编译器错误:

§ 14.8.2.5(从类型推导模板参数)第 5 段列出了无法推导模板参数的上下文。相关的是列表中的最后一个:

— A function parameter pack that does not occur at the end of the parameter-declaration-clause.

更新:

我想有人可以在最后放入一个虚拟参数,继续将第一个参数移到最后或将其扩展到前面(如果它是一个列表)并专注于第一个参数作为我的虚拟参数以停止递归。不过,对于编译器来说,仅仅为了展平一个列表似乎需要做很多工作。

namespace Detail{
struct MyMagicType {};
template<typename T, typename... Ts>
struct FlattenTree{
typedef typename FlattenTree<Ts..., T>::Type Type;
};
template<typename... Ts>
struct FlattenTree<MyMagicType,Ts...>{ //termination case
typedef List<Ts...> Type;
};
template<typename... Ts, typename... Us>
struct FlattenTree<List<Ts...>, Us...>{
typedef typename FlattenTree<Ts..., Us...>::Type Type;
}; //expand Ts to front because they may hold more nested Lists
}

template<typename... Ts>
struct FlattenTree{
typedef typename Detail::FlattenTree<Ts...,Detail::MyMagicType>::Type Type;
};

这适用于 MSVC2013,但我认为这不是最好的方法,因为我需要一个虚拟类型并且它会给编译器带来很多负担。我想将它用于包含 500 多个元素的列表。

最佳答案

另一种方法是使用辅助类和累加器列表代替 MyMagicType .我们从一个空的 List<> 开始然后用输入列表中的类型填充它:

#include <type_traits>

template <class... Ts> struct List {};

// first parameter - accumulator
// second parameter - input list
template <class T, class U>
struct flatten_helper;

// first case - the head of the List is List too
// expand this List and continue
template <class... Ts, class... Heads, class... Tail>
struct flatten_helper<List<Ts...>, List<List<Heads...>, Tail...>> {
using type = typename flatten_helper<List<Ts...>, List<Heads..., Tail...>>::type;
};

// second case - the head of the List is not a List
// append it to our new, flattened list
template <class... Ts, class Head, class... Tail>
struct flatten_helper<List<Ts...>, List<Head, Tail...>> {
using type = typename flatten_helper<List<Ts..., Head>, List<Tail...>>::type;
};

// base case - input List is empty
// return our flattened list
template <class... Ts>
struct flatten_helper<List<Ts...>, List<>> {
using type = List<Ts...>;
};

// wrapper around flatten_helper
template <class T> struct flatten;

// start with an empty accumulator
template <class... Ts>
struct flatten<List<Ts...>> {
using type = typename flatten_helper<List<>, List<Ts...>>::type;
};

auto main() -> int {
using Types = List<int, List<float, List<double, List<char>>>>;
using Flat = flatten<Types>::type;

static_assert(std::is_same<Flat, List<int, float, double, char>>::value, "Not the same");
}

关于c++ - 如何使用 Variadic 模板来展平类型树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19838965/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com