关于模板原编程知识强烈推荐: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的方式实现变长参数