C++之模板元编程

关于模板原编程知识强烈推荐:http://blog.jobbole.com/83461/,非常好!


这篇文章通过举例详细介绍了模板的模板参数,模板特例化,模板实例化以及编译链接等模板基础知识。

本文主要分析文章中的模板元编程例子:

首先复述一下模板元编程,以下标红或者加粗的地方是模板元编程的精髓:

从编程范型(programming paradigm)上来说,C++ 模板是函数式编程(functional programming),它的主要特点是:函数调用不产生任何副作用(没有可变的存储),用递归形式实现循环结构的功能。C++ 模板的特例化提供了条件判断能力,而模板递归嵌套提供了循环的能力,这两点使得其具有和普通语言一样通用的能力(图灵完备性)。

编程形式来看,模板的“<>”中的模板参数相当于函数调用的输入参数模板中的 typedef 或 static const 或 enum 定义函数返回值(类型或数值,数值仅支持整型,如果需要可以通过编码计算浮点数),代码计算是通过类型计算进而选择类型的函数实现的(C++ 属于静态类型语言,编译器对类型的操控能力很强)

模板下的控制结构:

template < bool c , typename Then , typename Else > class IF_ { } ;
template < typename Then , typename Else >
class IF_ < true , Then , Else > { public : typedef Then reType ; } ;
template < typename Then , typename Else >
class IF_ < false , Then , Else > { public : typedef Else reType ; } ;
 
// 隐含要求: Condition 返回值 ret,Statement 有类型 Next
template < template < typename > class Condition , typename Statement >
class WHILE_ {
     template < typename Statement > class STOP { public : typedef Statement reType ; } ;
public :
     typedef typename
         IF_ < Condition < Statement > :: ret ,
         WHILE_ < Condition , typename Statement :: Next > ,
         STOP < Statement >> :: reType :: reType
     reType ;
} ;

template < int n , int e >
class sum_pow {
     template < int i , int e > class pow_e { public : enum { ret = i * pow_e < i , e - 1 > :: ret } ; } ;
     template < int i > class pow_e < i , 0 > { public : enum { ret = 1 } ; } ;
     // 计算 i^e,嵌套类使得能够定义嵌套模板元函数,private 访问控制隐藏实现细节
     template < int i > class pow { public : enum { ret = pow_e < i , e > :: ret } ; } ;
     template < typename stat >
     class cond { public : enum { ret = ( stat :: ri <= n ) } ; } ;
     template < int i , int sum >
     class stat { public : typedef stat < i + 1 , sum + pow < i > :: ret > Next ;
                         enum { ri = i , ret = sum } ; } ;
public :
     enum { ret = WHILE_ < cond , stat < 1 , 0 >> :: reType :: ret } ;
} ;
 
int main ( ) {
     std :: cout << sum_pow < 10 , 2 > :: ret << '\n' ;
     std :: cin . get ( ) ; return 0 ;
}
//代码解析:

sum_pow<10,2>利用模板参数相当于函数调用的输入参数。::ret是函数的返回值,用enum或者static const定义的变量。1.函数调用WHILE_条件函数;2.WHILE_条件函数调用其返回类型reType;3. WHILE_条件函数调用IF_函数;4.IF_函数需要判断cond的布尔值;5.由于WHILE_函数首先执行stat<1,0>函数;6.stat<1,0>会设置ri=1; 7.cond函数的返回值为true;8. IF_函数返回THEN类型,即在此执行WHILE_函数。整个模板的执行过程就是1+ 2*2 + 3*3* +....+10*10= 385

在讲元容器之前,我们先来看看伪变长参数模板(文献[1] 12.4),一个可以存储小于某个数(例子中为 4 个)的任意个数,任意类型数据的元组(tuple)的例子如下(参考了文献[1] 第 225~227 页):

#include <iostream>
 
class null_type { } ; // 标签类,标记参数列表末尾
template < typename T0 , typename T1 , typename T2 , typename T3 >
class type_shift_node {
public :
     typedef T0 data_type ;
     typedef type_shift_node < T1 , T2 , T3 , null_type > next_type ; // 参数移位了
     static const int num = next_type :: num + 1 ; // 非 null_type 模板参数个数
     data_type data ; // 本节点数据
     next_type next ; // 后续所有节点数据
     type_shift_node ( ) : data ( ) , next ( ) { } // 构造函数
     type_shift_node ( T0 const & d0 , T1 const & d1 , T2 const & d2 , T3 const & d3 )
         : data ( d0 ) , next ( d1 , d2 , d3 , null_type ( ) ) { } // next 参数也移位了
} ;
template < typename T0 > // 特例,递归终止
class type_shift_node < T0 , null_type , null_type , null_type > {
public :
     typedef T0 data_type ;
     static const int num = 1 ;
     data_type data ; // 本节点数据
     type_shift_node ( ) : data ( ) , next ( ) { } // 构造函数
     type_shift_node ( T0 const & d0 , null_type , null_type , null_type ) : data ( d0 ) { }
} ;
// 元组类模板,默认参数 + 嵌套递归
template < typename T0 , typename T1 = null_type , typename T2 = null_type ,
         typename T3 = null_type >
class my_tuple {
public :
     typedef type_shift_node < T0 , T1 , T2 , T3 > tuple_type ;
     static const int num = tuple_type :: num ;
     tuple _type t ;
     my_tuple ( T0 const & d0 = T0 ( ) , T1 const & d1 = T1 ( ) , T2 const & d2 = T2 ( ) , T3 const & d3 = T3 ( ) )
         : t ( d0 , d1 , d2 , d3 ) { } // 构造函数,默认参数
} ;
 
// 为方便访问元组数据,定义 get<unsigned>(tuple) 函数模板
template < unsigned i , typename T0 , typename T1 , typename T2 , typename T3 >
class type_shift_node_traits {
public :
     typedef typename
         type_shift_node_traits < i - 1 , T0 , T1 , T2 , T3 > :: node_type :: next_type node_type ;
     typedef typename node_type :: data_type data_type ;
     static node_type & get_node ( type_shift_node < T0 , T1 , T2 , T3 > & node )
     { return type_shift_node_traits < i - 1 , T0 , T1 , T2 , T3 > :: get_node ( node ) . next ; }
} ;
template < typename T0 , typename T1 , typename T2 , typename T3 >
class type_shift_node_traits < 0 , T0 , T1 , T2 , T3 > {
public :
     typedef typename type_shift_node < T0 , T1 , T2 , T3 > node_type ;
     typedef typename node_type :: data_type data_type ;
     static node_type & get_node ( type_shift_node < T0 , T1 , T2 , T3 > & node )
     { return node ; }
} ;
template < unsigned i , typename T0 , typename T1 , typename T2 , typename T3 >
typename type_shift_node_traits < i , T0 , T1 , T2 , T3 > :: data_type
get ( my_tuple < T0 , T1 , T2 , T3 > & tup ) {
     return type_shift_node_traits < i , T0 , T1 , T2 , T3 > :: get_node ( tup . t ) . data ;
}
 
int main ( ) {
     typedef my_tuple < int , char , float > tuple3 ;
     tuple3 t3 ( 10 , 'm' , 1.2f ) ;
     std :: cout << t3 . t . data << ' '
               << t3 . t . next . data << ' '
               << t3 . t . next . next . data << '\n' ;
     std :: cout << tuple3 :: num << '\n' ;
     std :: cout << get < 2 > ( t3 ) << '\n' ; // 从 0 开始,不要出现 3,否则将出现不可理解的编译错误
     std :: cin . get ( ) ; return 0 ;
}

//变长参数利用的就是循环,通过将参数移位,然后设定null_type的方式实现变长参数

猜你喜欢

转载自blog.csdn.net/w1012747007/article/details/76222535
今日推荐