从具有相同容器类型但不同 value_type 的容器生成新类型
generate new type from container having same container type but different value_type
给定一个容器,例如 std::list<T>
或 std::vector<T>
,我想在我不知道的情况下分别生成一个新类型 std::list<NewT>
或 std::vector<NewT>
容器(std::list
或 std::vector
)提前。
我当前(但 failing)的尝试如下所示:
#include <list>
#include <vector>
template<class Cont, class NewT> struct SameContNewT : public std::false_type
{};
template<class T, class Alloc, class NewT>
struct SameContNewT<std::list<T, Alloc>, NewT>
{ typedef typename std::list<NewT> type; };
template<class T, class Alloc, class NewT>
struct SameContNewT<std::vector<T, Alloc>, NewT>
{ typedef typename std::vector<NewT> type; };
int main()
{
typedef std::list<int> IntList;
typedef std::list<float> FloatList;
typedef SameContNewT<IntList, float> FloatListToo;
static_assert(std::is_same<FloatListToo, FloatList>::value, "No.");
}
如何实现预期的行为?
一些模板模板参数稍后会出现...
template <class T, class NewP>
struct SameContNewT;
template <template <class...> class T, class... TPs, class NewP>
struct SameContNewT<T<TPs...>, NewP> {
using type = T<NewP>;
};
这确实丢弃了原始类型的所有模板参数,例如标准容器的分配器。这些需要更多的东西,因为你不能重用 T
的分配器,它很可能是 std::allocator<typename T::value_type>
并且不适合分配 NewT
。
您想要的类型不是 SameContNewT<IntList, float>
,而是它的嵌套类型 type
。您可以直接使用
修复该问题
typedef SameContNewT<IntList, float>::type FloatListToo;
...或使用别名模板:
template <typename Cont, typename New>
using SameContNew = typename SameContNewT<Cont, New>::type;
... 并删除 T
.
如果你想花点心思对一个几乎任意的容器进行操作,你也可以使用类似的东西:
template <template <typename...> class Cont, typename... T, typename New>
struct SameContNewT<Cont<T...>, New>
{ typedef Cont<New> type; };
但是,使用这种专业化只会使方法更加通用。它没有解决原来的问题。
template<class Z, class...Ts>
struct rebind_types;
template<class Z, class...Ts>
using rebind_types_t=typename rebind_types<Z,Ts...>;
template<template<class...>class Z, class...Us, class...Ts>
struct rebind_types<Z<Us...>, Ts...>{
using type=Z<Ts...>;
};
现在我们得到:
typedef std::list<int> IntList;
typedef std::list<float> FloatList;
typedef rebind_types_t<IntList, float> FloatListToo;
static_assert(std::is_same<FloatListToo, FloatList>::value, "No.");
并且我们可以将多个类型参数传递给 rebind_types_t
。我们"gut"传递了模板实例,并给它新的参数。
对于特定于容器的版本,您必须了解分配器等的参数(分配器有办法重新绑定到新类型)。处理关联容器的比较器和哈希之类的事情变得棘手。
给定一个容器,例如 std::list<T>
或 std::vector<T>
,我想在我不知道的情况下分别生成一个新类型 std::list<NewT>
或 std::vector<NewT>
容器(std::list
或 std::vector
)提前。
我当前(但 failing)的尝试如下所示:
#include <list>
#include <vector>
template<class Cont, class NewT> struct SameContNewT : public std::false_type
{};
template<class T, class Alloc, class NewT>
struct SameContNewT<std::list<T, Alloc>, NewT>
{ typedef typename std::list<NewT> type; };
template<class T, class Alloc, class NewT>
struct SameContNewT<std::vector<T, Alloc>, NewT>
{ typedef typename std::vector<NewT> type; };
int main()
{
typedef std::list<int> IntList;
typedef std::list<float> FloatList;
typedef SameContNewT<IntList, float> FloatListToo;
static_assert(std::is_same<FloatListToo, FloatList>::value, "No.");
}
如何实现预期的行为?
一些模板模板参数稍后会出现...
template <class T, class NewP>
struct SameContNewT;
template <template <class...> class T, class... TPs, class NewP>
struct SameContNewT<T<TPs...>, NewP> {
using type = T<NewP>;
};
这确实丢弃了原始类型的所有模板参数,例如标准容器的分配器。这些需要更多的东西,因为你不能重用 T
的分配器,它很可能是 std::allocator<typename T::value_type>
并且不适合分配 NewT
。
您想要的类型不是 SameContNewT<IntList, float>
,而是它的嵌套类型 type
。您可以直接使用
typedef SameContNewT<IntList, float>::type FloatListToo;
...或使用别名模板:
template <typename Cont, typename New>
using SameContNew = typename SameContNewT<Cont, New>::type;
... 并删除 T
.
如果你想花点心思对一个几乎任意的容器进行操作,你也可以使用类似的东西:
template <template <typename...> class Cont, typename... T, typename New>
struct SameContNewT<Cont<T...>, New>
{ typedef Cont<New> type; };
但是,使用这种专业化只会使方法更加通用。它没有解决原来的问题。
template<class Z, class...Ts>
struct rebind_types;
template<class Z, class...Ts>
using rebind_types_t=typename rebind_types<Z,Ts...>;
template<template<class...>class Z, class...Us, class...Ts>
struct rebind_types<Z<Us...>, Ts...>{
using type=Z<Ts...>;
};
现在我们得到:
typedef std::list<int> IntList;
typedef std::list<float> FloatList;
typedef rebind_types_t<IntList, float> FloatListToo;
static_assert(std::is_same<FloatListToo, FloatList>::value, "No.");
并且我们可以将多个类型参数传递给 rebind_types_t
。我们"gut"传递了模板实例,并给它新的参数。
对于特定于容器的版本,您必须了解分配器等的参数(分配器有办法重新绑定到新类型)。处理关联容器的比较器和哈希之类的事情变得棘手。