【问题标题】:generate new type from container having same container type but different value_type从具有相同容器类型但不同 value_type 的容器生成新类型
【发布时间】:2015-11-20 13:41:30
【问题描述】:

给定一个容器,例如std::list<T>std::vector<T>,我想在我不知道容器(std::liststd::vector)的情况下分别生成一个新类型std::list<NewT>std::vector<NewT> ) 提前。

我当前(但 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.");
}

如何实现预期的行为?

【问题讨论】:

    标签: c++ templates c++11 c++14 template-meta-programming


    【解决方案1】:

    一些模板模板参数在后面玩弄...

    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&lt;typename T::value_type&gt; 并且不适合分配 NewT 的。

    【讨论】:

      【解决方案2】:

      您想要的类型不是SameContNewT&lt;IntList, float&gt;,而是它的嵌套类型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; };
      

      但是,使用这种专业化只会使方法更通用。它不能解决原来的问题。

      【讨论】:

      • 哦,当然。非常感谢。我现在觉得自己很蠢。
      【解决方案3】:
      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。我们“消化”传递的模板实例,并给它新的参数。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-28
        • 1970-01-01
        • 1970-01-01
        • 2011-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多