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