设为首页 加入收藏

TOP

使用模板元编程操作类型集合(C++11下的TypeList)(一)
2015-07-24 07:12:06 来源: 作者: 【 】 浏览:250
Tags:使用 模板 编程 操作 类型 集合 TypeList

Wrote by mutouyun. (http://darkc.at/cxx-type-list/)

群里有个朋友要实现这么一个功能:如何在编译期把一个函数类型的参数减少一个。
简单来说,就是实现下面这个模板:

remove_func_par<2, void(int, long, short)>::type; // type = void(int, long)

根据输入的编译期整数,把函数参数表里对应的参数干掉一个。
为了实现这种功能,我们需要操作变参模板的参数包。比如像这样:

// make function's parameters from the types
 
template 
  
   
struct make_func_par;
 
template 
   
     struct make_func_par
    
     > { typedef R type(P...); }; // remove function's parameter template 
     
       struct remove_func_par; template 
      
        struct remove_func_par
       
         { using erase_pars_t = typename types_erase
        
         , N>::type; using type = typename make_func_par
         
          ::type type; };
         
        
       
      
     
    
   
  

上面这段代码的思想很简单,把模板参数包的第N个参数删掉,然后再将它重新展开成函数的参数表。而types的定义可以非常简单:

template 
  
   
struct types {};
  

如果定义了一组对types类型做操作的算法,那么我们就可以把参数包放入types中,然后对它做这样那样的事情。。

看到这里,不知道有没有朋友想起来很久很久以前,Loki库里的TypeList。现代的C++当然不需要再像当年那样用外敷类和繁琐的宏来实现这个,使用变参模板加模板元就好了。

一、types的判断和大小计算

有了上面types的定义之后,下面需要实现一些算法来操作它。首先,在不涉及到容器的查找修改时,最基本的算法简单来说有下面几个:判断容器类型(因为容器是编译期的一个类型)、计算容器大小、判断容器是否是空的。下面我们来依次实现它们。

判断算法非常简单:

/*
    Is types
*/
 
template 
  
   
struct is_types
     : std::false_type
{};
 
template 
   
     struct is_types
    
     > : std::true_type {};
    
   
  

有了判断的算法之后,对于后面的运算就可以在编译时判断出传入的类型是否符合要求。我们可以定义一个专门用来判断类型合法性的模板:

// Check is types or not
 
template 
  
   
struct check_is_types
{
    static_assert(is_types
   
    ::value, "The template parameter is not a types-list!"); };
   
  

在需要的时候,继承check_is_types就好了。
接下来,是计算types的大小。在有了变参模板,以及针对模板参数包的sizeof运算符以后,这个工作也是非常简单的:

/*
    Return size
*/
 
template 
  
   
struct types_size : std::integral_constant
   
     , check_is_types
    
      {}; template 
     
       struct types_size
      
       > : std::integral_constant
       
         {};
       
      
     
    
   
  

通过继承check_is_types,types_size在传入参数不是一个types的时候,会在编译时报出错误提示。
有了计算types大小的工具,我们可以为后面的算法再准备两个编译时合法性判断的辅助类:

// Check is index valid or not
 
template 
  
   
struct check_is_index_valid
{
    static_assert(IndexN >= 0,                        "Index is out of range!");
    static_assert(IndexN < types_size
   
    ::value, "Index is out of range!"); }; // Check is count valid or not template 
    
      struct check_is_count_valid { static_assert(CountN > 0, "Count is too small!"); static_assert(CountN <= types_size
     
      ::value, "Count is too large!"); };
     
    
   
  

check_is_index_valid用来判断传入的索引是否超出了指定types的范围;
check_is_count_valid用来判断传入的大小是否超出了指定types的大小。
和check_is_types一样,在需要的时候继承这两个类模板就可以了。

然后,是容器是否为空的判断:

/*
    Test whether types is empty
*/
 
template 
  
   
struct types_empty : std::true_type
                   , check_is_types
   
     {}; template 
    
      struct types_empty
     
      > : std::false_type {}; template <> struct types_empty
      
       > : std::true_type {};
      
     
    
   
  

二、types的元素访问

types的访问算法就是根据传入的索引(index)定位类型。我们可以先写下types_at的定义:

template 
  
   
struct types_at : check_is_index_valid
   
     { using type = TypesT; };
   
  

接下来,是思考如何通过模板元的递归定位元素了。在数学里,最基本的定位方法就是数个数(是的,你没听错,就是数数)。模板元在递归的时候,每次可以去掉参数包中开头的第一个参数,同时我们让传入的index减1。当index为0的时候,对应的参数类型就是我们需要的类型了。算法实现可以像这样:

template 
  
   
struct types_at
   
    , N> : types_at
    
     , N - 1> {}; template 
     
       struct types_at
      
       , 0> { using type = T1; };
      
     
    
   
  

上面的第一个types_at特化负责把参数包和index同时减1,并传入下一层;最后模板的递归会在第二个types_at特化处终结。
我们看到,这里并不需要一个types<>的特化。因为当传入的模板参数是types<>的时候,它不会匹配到任何一个特化,因此最初的types_at定义就可以搞定这种情况了。

有了types_at之后,我们可以很方便的实现front和back的定位算法:

/*
    Access first element
*/
 
template 
  
   
struct types_front
{
    using type = types_at_t
   
    ; }; /* Access last element */ template 
    
      struct types_back { using type = types_at_t
     
      ::value - 1>; };
     
    
   
  

三、types的连接(Link)和

首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Codeforces 427 D. Match & C.. 下一篇ZOJ 1457 Prime Ring Problem(df..

评论

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