【问题标题】:template metaprogramming: (trait for?) dissecting a specified template into types T<T2,T3 N,T4, ...>模板元编程:(特征?)将指定的模板分解为类型 T<T2,T3 N,T4, ...>
【发布时间】:2012-07-30 14:33:18
【问题描述】:

我试图从类型E = T&lt;T2,T3&gt; 中推断出底层模板类型T。例如,这可以使模板函数pair_maker(const E & a) 可以与几种类似类型的容器之一一起使用。粗略的元代码:

template <typename T>
auto pairmaker(const E & a) -> PairContents<E,std::string>::type {
    ContainerPairMaker<E,std::string>::type output;
    ... some code ...
    return output;
}

PairContents&lt;E,std::string&gt;

会将vector&lt;int&gt; 类型转换为vector&lt;pair(int,std::string)&gt;whatever&lt;T1&gt; 转换为whatever&lt;pair(T1,std::string)&gt;

类型剖析的另一个类似示例是 std::array (或类似容器),我想找出 container 类型以创建一个新的类似数组。例如对于这些类型的函数(这是现在实际工作的代码)

template <typename T > 
auto make_some3(const T & a) 
           -> std::array<typename T::value_type,10*std::tuple_size<T>::value>{   
   return std::array<typename T::value_type,10*std::tuple_size<T>::value>{} ;
}

这很好用,但我想要的是自动显式使用“std::array”。

对于 std::array 有 tuple_size 特性有帮助,类似的东西可用于为任何第二个参数找到 type,但我还是想不出任何找到容器类型的方法。

总结一下:什么样的机器(如果有的话)可以用于这些情况。在何种程度上可以处理模板参数、模板-模板参数、任意数量的参数和未知类型的非模板参数的混合。

【问题讨论】:

  • 问题是,如果您重新绑定第一个参数,标准容器将有一个不匹配的分配器,也就是PairContent&lt;vector&lt;int, allocator&lt;int&gt;&gt;,float&gt;::type 将是vector&lt;pair&lt;int,float&gt;, allocator&lt;int&gt;&gt;
  • 作为术语,T&lt;T2, T3&gt; T 不是类型。您正在寻找的是基础类模板T,其中T&lt;T2, T3&gt; 是一个特化(和一个类型)。因此你不能让extract&lt;std::vector&lt;int&gt;&gt;::type 成为std::vector
  • Xeo,哦……这是个大问题。您为什么不将其带入您现在已删除的答案中?

标签: c++ templates c++11 metaprogramming


【解决方案1】:

这是一个想法:

 template <typename T, typename ...>
 struct tmpl_rebind
 {
     typedef T type;
 };

 template <template <typename ...> class Tmpl, typename ...T, typename ...Args>
 struct tmpl_rebind<Tmpl<T...>, Args...>
 {
     typedef Tmpl<Args...> type;
 };

用法:

typedef std::vector<int> IV;
typedef typename tmpl_rebind<IV, std::pair<double, std::string>>::type PV;

现在PV = std::vector&lt;std::pair&lt;double, std::string&gt;&gt;

【讨论】:

  • 我不知道指定的模板可以作为模板模板参数传递。
  • @JohanLundberg 他们不能——如果您将模板特化匹配为模式匹配,那么这里模板特化被解构为其主要模板和模板参数部分。看tmpl_rebind的主模板声明:第一个参数(typename T)实际上是模板类型参数,而不是模板模板参数。
  • @JohanLundberg:这不是我的答案,我只编辑了其中的一部分。 ;)
  • @JohanLundberg 这个答案没有那个问题。
  • Xeo,啊,是的,我只是打错了你的名字。 @Xeo,Kerrek,Luc,感谢您提供这些 cmets。好吧,在这种情况下,所有参数都是反弹的,所以那里没有旧的分配。我现在看到了。 typeid(PV) == typeid(PV2)
【解决方案2】:

这是我想出的一个自我答案,作为 Kerrek SB 答案的变体

可以创建一个从std::vector&lt;int&gt; 中提取std::vector 的特征,并通过特征将其公开为::type。是的,这个解决方案与 Kerrek 的解决方案几乎相同,但对我来说使用语法更美观,将模板参数放在 ::type 之后。

template <typename T, typename ...>
struct retemplate
{
    typedef T type;
};

template <template <typename ...> class Tmpl, typename ...T>
struct retemplate<Tmpl<T...>>
{
   template <typename ...AR>
   using type=Tmpl<AR...> ;
};

有了这个你实际上得到retemplate&lt;T&lt;A,B,C&gt;&gt;::type等于模板T

示例使用:

typedef std::vector<int> intvec; 
typedef retemplate<intvec>::type<double> doublevec; 

或者暴露容器类型

typedef std::vector<int> intv;
template <typename ...T>
using vector_T= retemplate<intv>::type<T...> ;

请注意,在模板上下文中使用它时,template 后面需要一个额外的::,如下所示:(详细说明 Xeo 的评论)

template <typename T>
typename retemplate<T>::template type<double> containedDouble(T& a) {
   decltype(containedDouble(a)) out;
   for (auto &i : a)
      out.push_back(i);
   return out;
}

这样做是获取T1&lt;T2&gt; 类型的对象并将其内容复制到T1&lt;double&gt;。例如T1==std::vectorT2==int

【讨论】:

  • 调用 snytax 在模板代码中变得有点丑陋,不过:typename retemplate&lt;intv&gt;::template type&lt;T...&gt;
  • 这很好。我还没有完全习惯新的usings :-)
  • @Xeo:为什么非要说template?那里没有从属名称,是吗 - intv 是一个实际类型。
  • @Kerrek:在模板中,你需要(显然用模板参数替换 intv,我失败了)。
  • @Xeo:是的,当然,如果你在依赖上下文中。干杯。不管怎样,谁不喜欢说很多::template来打动老板呢?
【解决方案3】:

我建议看一下A。 Alexandrescu 的书现代 C++ 设计

如果我没记错的话,他解释了如何使用类型列表以类似列表的方式存储和访问任意类型。这些列表可用于在多种不同情况下提供类型信息。查看Loki 的实现,了解如何使用类型列表。

我不确定这是否有帮助,但也许您可以从 Loki 中使用的想法中学到一些东西,以解决或至少更好地了解您手头的具体问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多