c++模版的一些使用方法(三)

c++模版的应用是可以分类的。按照用途,可以分为:

  1)工程模版

  2)算法和数据结构的解耦

  3)工作于编译期的模版

  4)XX的封装

  5)适配器模式

首先解释一下,这里的划分属于较高层的应用划分,但这些应用都是基于模版的一些共同特性的,比如带默认参数、特化和偏特化等。

分别解释一下就是:

(1)工程模版:《c++模版的一些使用方法(一)》中提到修改第三方库的应用属于这一类。工程模版主要是在大工程中的一些处理手法,不太好说。


(2)算法和数据结构的解耦就很清晰了,比如stl库,find算法既可以用于vector也可以用于list。再比如经常使用的单件模式,将它声明为几类,任何需要是单件模式的类只要从这个基类派生即可获得单件属性

template<typename T>
class Singleton
{
protected:
        Singleton(){}
public:
    static T& GetInstance()
        {
            static T Instance;
            return Instance; 
        }
};

class MyClass:public Singleton<MyClass>
{};


(3)工作于编译期的模版

由代码到可执行文件分为几个阶段:

No.1预处理阶段:处理#define,#ifdef,#include等预处理指令。它使在编译之前提供了一次修改源文件的机会,具有很大的灵活性。

No.2编译期:将源代码编成机器码,每个模块生成obj文件,

No.3链接器:将n个obj文件组合在一起,解析他们之间的交叉关系,得到可执行文件。

平时我们所说的执行效率,是指可执行文件处理一组数据的效率,可能还听说过在程序设计比赛中可以利用预处理来做一些事情,以此减少程序处理数据的时间,那么同样,有些事情是可以在编译期做的,同样可以通过把一些事情提前到编译期来提高程序的效率。

首先要明白哪些工作可以在编译期做:

No.1当有函数重载时,编译器在编译期决定调用哪个函数;

No.2sizeof操作符,typedef操作符,+ - = < > :?等运算符,等等等

No.3enum类型的赋值

No.4模版的特化、偏特化和实例化

那么,可以在编译期做哪些事呢?

我总结的有两点:

    1)计算一些数据

    2)生成代码

计算数据时,比如,可以这样计算Fibonacci数列:

template<int N>
struct Fibonacci
{
    enum
    {
        result = Fibonacci<N-1>::result+Fibonacci<N-2>::result
    };
};
template<>
struct Fibonacci<1>
{
    enum
    {
        result =1
    };
};
template<>
struct Fibonacci<0>
{
    enum
    {
        result =0
    };
};
int main()
{
    time_t t1=time(NULL);
    printf("%d\n",Fibonacci<40>::result);
    time_t t2=time(NULL);
    printf("UseTime:%d\n",t2-t1);
    return 1;
};
首先定义了一个模版,还有它的两个特化(针对1和0),接着调用Fiboncaai<40>::result,则编译器在编译时会尝试给模版中enum::result赋值,赋的是它后面那个表达式,而后面的表达式是一个另外两个模版的实例化,这同样也发生在编译期,所以编译器会继续跟下去,一直跟到Fiboncaai<1>::result+Fiboncaai<0>,然后编译器发现针对1和0是有模版特化的,于是它去调用特化,特化中定义了出口,于是赋值结束。可以将其理解为类递归,但不同的是,真正意义的递归是函数的嵌套调用本身,时间复杂度很高,而这里,由于在编译器,每次“递归”实质上是模版的实例化,而出口是模版的特化,所以不存在任何的函数嵌套调用。

上面Fiboncaai<40>输出的结果是102334155,反汇编看一下,如图:


编译器经过计算,直接在这里放了一个立即数,译成十进制正是102334155

而上面代码中所消耗的时间是0。如图


而经过测试,用普通的函数递归计算Fiboncaai的第40个,需要8秒的时间。

用于生成代码时,也可以成为模版的元编程,元编程是指某类计算机程序的编写,这类计算机程序编写或者操纵其他程序(或者自身)作为它们的数据,或者在编译时完成部分本应在运行时完成的工作。很多情况下比手工编写全部代码相比工作效率更高。编写元程序的语言称之为元语言,被操作的语言称之为目标语言。一门语言同时也是自身的元语言的能力称之为反射。

由上面的定义可知,元编程也是工作在编译期,其实上面的计算数据的应用,也可以归为元编程,因为编译器不断的实例化模版来“递归”,本质上也是在帮我们生成代码。Loki库中的Typelist就是使用模版元编程的经典之作。

XX的封装和适配器模式以后再说吧

发布了56 篇原创文章 · 获赞 21 · 访问量 26万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章