欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++之模板元编程

程序员文章站 2022-04-27 19:19:07
通过举例详细介绍了模板的模板参数,模板特例化,模板实例化以及编译链接等模板基础知识。 本文主要分析文章中的模板元编程例子: 首先复述一下模板元编程: 从编程范型(progra...

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

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

首先复述一下模板元编程:

从编程范型(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

在讲元容器之前,我们先来看看伪变长参数模板,一个可以存储小于某个数(例子中为 4 个)的任意个数,任意类型数据的元组(tuple)的例子如下:

#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的方式实现变长参数