设为首页 加入收藏

TOP

使用模板元编程操作类型集合(C++11下的TypeList)(三)
2015-07-24 07:12:06 来源: 作者: 【 】 浏览:251
Tags:使用 模板 编程 操作 类型 集合 TypeList
的特化条件是否是逐渐收窄的:

  
   , N, C>

   
    , 0, C> 
    
     , 0, 1>
    
   
  

那么是否所有的情况都考虑到了呢?通过枚举出所有的特化条件,我们发现只有types<>没有考虑。对于types_erase来说,types<>没有删除的意义,因此直接让它匹配到types_erase的定义就可以了。当然,这会引起一个编译期的static_assert,因为任何的index都将超出types<>的范围。

五、types的查找,以及其它算法

查找算法的需求如下:
给定一个types和类型T,需要在types中找到T所在的第一个索引位置。
首先,我们先写出定义:

template 
  
   
struct types_find : std::integral_constant
   
     , check_is_types
    
      {};
    
   
  

接着,我们用数学归纳法的方式来思考:
当types中的第一个元素为T时,索引位置为0;(终结条件)
当types中的第N个元素为T时,索引位置为上一个元素的索引加1。

那么我们可以先列出需要特化的版本:

  
   , T1>

   
    , U>
   
  

接下来,先特化终结条件:

template 
  
   
struct types_find
   
    , T1> : std::integral_constant
    
      {};
    
   
  

然后思考一般情况:索引位置为上一个元素的索引加1,说明我们需要做一个加法。而find的结果有两种:找到了,和没找到。当没找到的时候,模板最终会匹配到types_find的定义上去。而我们在定义里给出的value是-1。因此在做加法运算时,需要把-1的情况忽略掉:

template 
  
   
struct types_find
   
    , U> : std::integral_constant
    
     , U>::value == -1 ? -1 : types_find
     
      , U>::value + 1)> {};
     
    
   
  

有了查找算法以后,判断types中是否存在某个类型就非常简单了:

template 
  
   
struct types_exist
     : std::integral_constant
   
    ::value != -1)> {};
   
  

接下来,让我们思考一个一般化的算法:
逐个遍历给定types中的元素,当该元素满足某个条件时,对这个元素做某件事情。
我们可以把定义写成下面这样:

template 
  
    class If_, typename V,
template 
   
     class Do_, typename U> struct types_do_if : check_is_types
    
      { using type = TypesT; };
    
   
  

If_用来把types中的某个类型T1,和给定的V做判断;Do_将接受If_的判断结果,对T1和U一起做某件事(比如置换)。
上面这句话说出来可能有点绕口,实际上写成代码并不复杂:

using done = typename Do_
  
   ::value, U, T1>::type;
  

我们从这里可以得到处理后的结果类型done。那么一般化的算法就是把done和剩下的(T1以外的)元素连起来。需要注意的是,处理是递归的,因此最后写出来应该是这个样子:

template 
  
    class If_, typename V,
template 
   
     class Do_, typename U> struct types_do_if
    
     , If_, V, Do_, U> { private: using tail = typename types_do_if
     
      , If_, V, Do_, U>::type; using done = typename Do_
      
       ::value, U, T1>::type; public: using type = typename types_link
       
        ::type; };
       
      
     
    
   
  

费这么大劲写这个一般化的算法有什么用呢?下面我们来看看它的威力。

首先,是types的置换算法:
给定一个types,以及类型T,U;要求把所有types中的T都换成U。
有了上面的types_do_if,实现这个算法非常轻松:

template 
  
   
struct types_replace
     : types_do_if
   
     {};
   
  

当在types中找到类型T的时候,就把它变成U。代码和语言描述基本是一致的。

接下来,考虑一个移除的算法:
给定一个types,和类型T,要求从types中移除所有的T。
通过types_do_if实现如下:

template 
  
   
struct types_remove
     : types_do_if
   
    > {};
   
  

我们可以看到,上面std::conditional后面的类型是types<>。原因是types_do_if里使用types_link连接结果。那么直接给定一个空的types,它和类型U连接后的结果仍然是U。
看到这里,我们其实可以写得更简单点:

template 
  
   
struct types_remove
     : types_replace
   
    > {};
   
  

使用types<>置换掉types里的T,结果和移除是一样的。
这里再思考一步:如果需要移除的类型T本身,也是一个types列表,那么我们可以批量移除掉多个类型。实现算法其实很简单:

template 
  
   
struct types_remove
   
    > { private: using rm_t = typename types_remove
    
     ::type; public: using type = typename types_remove
     
      >::type; };
     
    
   
  

从types 中取出一个元素做types_remove,把结果和剩下的types 放到递归里就可以了。

通过types_do_if还可以实现很多特殊操作,在这里就不再展开了。
接下来,我们实现types的“压缩”算法。当types里有多个重复元素的时候,如何把重复的内容剔除掉,只保留一个呢?
同样的,我们先写出定义:

template 
  
   
struct types_compact : check_is_types
   
     { using type = TypesT; };
   
  

如何判断内容有重复?其实很简单,当我们从types中取出一个元素T1,那么剩下的内容里,所有的T1都将是重复的,删掉就可以了。
算法写出来就是这样:

template 
  
   
struct types_compact
   
    > { private: using rm_t = typename types_remove
    
     , T1>::type; using tail = typename types_compact
     
      ::type; public: using type = typename types_link
      
       ::type; };
      
     
    
   
  

最后,一个特殊且有用的算法是倒序(reverse),即把types中的元素倒过来。实现如下:

template 
  
   
struct types_reverse : check_is_types
   
     { using type = TypesT; }; template 
    
      struct types_reverse
     
      > { private: using head = typename types_reverse
      
       >::type; public: using type = type
首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Codeforces 427 D. Match & C.. 下一篇ZOJ 1457 Prime Ring Problem(df..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: