从具有相同容器类型但不同 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::liststd::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>;
};

Live on Coliru

这确实丢弃了原始类型的所有模板参数,例如标准容器的分配器。这些需要更多的东西,因为你不能重用 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"传递了模板实例,并给它新的参数。

对于特定于容器的版本,您必须了解分配器等的参数(分配器有办法重新绑定到新类型)。处理关联容器的比较器和哈希之类的事情变得棘手。