C++模板

原创 2005年05月22日 18:05:00

C++模板

模板首先是一种设计理念,其次才是一种C++语法。只有先理解了模板,才能更好的使用C++中的模板特性。

模板的概念

为了能理解模板,可以先了解一下模具:为了生产一种产品,例如茶具,需要先设计其模具,有了模具后,能够轻易地成批量的生产出成千上万的产品。模具的特点是一次设计,反复使用。模具具有了模板的重用性特点;但却少了可扩展的特点:其产品是一成不变的,如果某人想把茶具的外形少作改动,则此模具就作废了。

为了兼有重用性和可扩展的优点,需要将不变的部分和变化的部分分开,把不变的部分做成模具骨架,把变化的部分作为模具的子部分存在。例如对汽车,可以认为车架、油路系统、电路系统,轮胎构成了一辆汽车的骨架,至于是什么样的车架、油路系统、电路系统在骨架中不体现出来,只是把这些部分的接口数据全定义出来了,只要满足这些定义的子部分部件,都能往骨架中放。可以这么简单的理解:骨架都有一些占位符组成,占位符组成有其定义,符合这些占位符定义的符号都能放入骨架中,以实现不同的功能。

现在把模板的定义上升到理论高度:“定义一个操作中算法的骨架,而将一些步骤延迟到子类中”[1];“各子类的公共行为被提前提取出并集中到一个公共父类中避免代码重复”[1]

需要说明的是,这里所说的子类不是只对模板类的派生,而是指模板类的参数化类别。模板已是设计模式[1]之一;模板通常有两个角色:

抽象类:定义抽象的原语操作(可以简单的定义了一些接口),其具体实现放到子类中;

具体类:实现原语操作以完成算法中与特定子类相关的步骤,即实现抽象类定义的接口。

模板的语法

C++中,分两个层次使用模板:模板函数,模板类。

模板函数

一般在头文件中定义模板函数,如

#ifndef _POS_H_

#define _POS_H_

template<class T>

T* pos(cosnt T& value, T* beginT* end)

{

for(; begin < end; begin ++)

{

    if(*begin == value)

{

    return begin;

}

 

}

}

#endif

要使用模板函数,需要对模板函数进行实例化,如下的例子使模板被实例化两次:

#include “pos.h”

#include <string>

using namespace std;

int main(int argc, char ** argv)

{

int int_array[30];

string string_array[30];

int iptr = pos(-1, &int_array[0], &int_array[30]);

string* sptr = pos(string(“sam”, &string_array[0], &string_array[30]);

    return 0;

}

模板类

模板类的定义与模板函数类似,可以把模板类的成员函数与类定义一起放到头文件中,如:

#ifndef _VECTOR_H_

#define _VECTOR_H_

template <class T>

class Vector

{

};

 

template <class T>

vector<T>::vector():tptf(new T[10], length(10){}

//对于在cpp文件中的实现方式同样需要如此定义

#endif

模板类的使用也类似,如:

#include <Vector.h>

int main(int argc, char** argv)

{

Vector<int> int_vec;

Vector<string> str_vec;

return 0;

}

模板特化

模板特化分两种:完全特化和偏特化;完全特化是模板的一种穷举方式,是指参数的完全固定化,即所以参数都有一个具体的类型,如:

template<bool> struct CompileTimeChecker{};

template<> struct CompileTimeChecker<true>

{

CompileTimeChecker(…){};

};

后者即是模板类CompileTimeChecker类的特化版本,因为它把bool类型的参数固定为true

而偏特化与完全特化是想对的,只有一个参数的模板类,无法偏特化;这是因为偏特化只能固定模板类的部分参数,而非全部(如果是全部,就变成了完全特化了)。如:

template<class T, class U>

class Conversion

{

};

template <class T>

class Conversion<T, T>

{

public:

    enum{exists = 1, sameType = 1};

}

后者实现了对模板类Conversion的偏特化版本,即两个参数TU类型相同的情况。Visual C++ 6不支持对模板类的偏特化。

type traits

Type Traits是范型编程中用于编译是类型判断的一项技术,其主要思想是利用函数特化(特别是完全特化),来为模板类定义一些辅助常量和函数,以便于在编译时进行类型判断。例如,想对指针和非指针类型做区分,以编译进行不同的处理,就可以使用Type Traits技术。

Template <typename T>

Class TypeTraits

{

private:

   template<class U>struct PointerTraits

   {

enum{result = false;};

typedef NullType PointeeType;

   };

   template<class U> struct PointerTraits<U*>

{

   enum{result = true ;};

  typedef U PointeeType;

;

public:

enum{isPointer = PointerTraits::result};

typedef PointerTraits<T>::PointeeType PointeeType;

};

上面的例子,把非指针类型定义其枚举变量resultfalse,这是一种范型结果;而对指针类型,利用特化版本,另外定义其结果为true;为了对外有一致的接口,对非指针类型用了一个空指针占位NullType,并都定义了类型PointeeType。在模板实例化时,会根据不同的参数类型调用不同的版本。

TypeTraits的主要用途主要是用于代码优化,因为如果知道类型后,就能利用特殊方法进行处理。如对char的复制,可以直接使用memcpy,这是C++中最快的复制方式;对有双CPU的机器,可以使用直接比特流复制等。

模板与编译器

编译器怎么样实现模板的呢?

²        编译:在编译如上的例子程序时,编译器从pos.h中读到了模板定义,并根据在main中实例化的情况,编译器会自动生成两个版本的pos函数:pos(const int&, int*, int*)pos(string&, string*, string*)

²        Borland C++VC Sun Workshop HP aCCG++:编译器在main.o或者main.obj中扩展pos函数两次。

²        EDG-based C++或者G++-frepo参数:编译器直到链接时才展开pos函数,但编译时会在本地数据库(EDGmain.ii-实例化信息文件,G++main.pro-仓库文件)中生产记录参数化信息。

模板的副作用

模板是好东西,但也有其副作用,世界就是这么公平:

对于链接时实例化:链接更加耗时;在实例化时会递归很多此来得到所以成员函数的全部版本。

对眼编译时实例化:目标代码变大;很难有选择地实例化模板类成员函数地几个版本,即实现全部版本。

会带来不必要的代码编写,如模板类中实现了操作符<<,并在其中引用此操作符,在实例化模板类时,编译器会要求你的类实现此操作符,即是你的应用程序根本不会使用此操作符,否则编译失败。

结束语

模板技术常用于类库编程和范型编程,因为其主要思想是提炼算法骨干,延迟细节处理;使用好了模板将使类库代码短小精悍;模板读设计思路是一种抽象和复用,能够提高设计的效率。

参考书目

²        [1] STL源码剖析,侯捷。

²        [2] C++ 设计新思维,Andrei Alexandrescu.

C++模板类的继承1 :模板类继承模板类

大学时代旧作。       模板类的继承是C++中较为高级的一种用法,其语法与普通C++类的继承略有差别。本文实例演示了一个通过C++模板类继承实现排序算法的案例。代码如下: 1.   实现List基...
  • u011747351
  • u011747351
  • 2013年08月25日 13:53
  • 1223

C++使用模板特化实现工厂模式

许多C++程序员使用简单工厂创建自己的对象,这时就会有很多这样的分支,比如: class Staff { virtual double salary() = 0;//薪酬 } class Engi...
  • qingcaichongchong
  • qingcaichongchong
  • 2016年03月17日 16:17
  • 732

c++学习(模板特化和偏特化)

模板特化和偏特化作者:谢宝陵  周 生(合肥市炮兵学院计算中心 230031)摘要:本文通过例子介绍了在 C++标准库中广泛使用的模板特化和偏特化,并指出了模板特化和偏特化的定义规则和应用规则。关键词...
  • zhang810413
  • zhang810413
  • 2007年12月18日 22:26
  • 12271

链表——用C++模板实现

LinkedList.h//单向链表的实现 //查找、插入和移除某个元素、复制、清空单向链表的时间复杂度均为O(n) //设计类时,应尽量减少类的成员函数之间的依赖关系 #ifndef LINK...
  • Microsues
  • Microsues
  • 2010年12月29日 20:02
  • 12425

c++模板参数自动推导

上次,我们看了什么是模板函数,今天,我们就从这个模板函数入手,继而引出一个新的知识点-模板参数自动推导。为了介绍清楚什么是模板参数自动推导,我们先定义几个术语,通过这些术语来描述比较方便,这些术语是:...
  • u010956473
  • u010956473
  • 2017年06月21日 09:12
  • 594

C++ 类模板概念与实例,模板参数问题

什么是类模板? 一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。 ...
  • qq_26437925
  • qq_26437925
  • 2016年12月18日 15:33
  • 1352

c++模板链表实现

简介:主要是利用模板实现链表的操作。模板的使用,使得程序的开发量大大地减少。 可以先定义一个链表LinkList,之后可以定义自己的类了(例如:Student类),使用时就可以这样调用了 LinkLi...
  • invisible_sky
  • invisible_sky
  • 2016年03月24日 17:48
  • 934

C++双重模板

Template Template Paraments(双重模板参数)模板参数本身也可以是一个类模板,例如实现一个Stack class。为了使用其他类型的元素容器,使用者必须两次指定元素类型:一次是...
  • GuFanYuan
  • GuFanYuan
  • 2016年01月16日 16:12
  • 316

C++模板参数为数组

本想写个模板函数,然后导成DLL,然后可以到处引用。可是后来发现,我的想法很天真。 由于C++是强类型语言,所以模板在用的时候必须确定其类型。而C++的模板只是一种语法糖,只不过是编译器在后台在做字...
  • ec06cumt
  • ec06cumt
  • 2012年11月07日 15:31
  • 1393

C++模板实现的单向链表

C++模板实现的单向链表,实现了链表的初始化创建,元素插入,元素链表末尾添加,元素删除,链表清空 //Lists.h #ifndef DDXXLISTS_H #define DDXXLISTS_H #...
  • zhuhuangtianzi
  • zhuhuangtianzi
  • 2014年02月27日 00:57
  • 1407
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++模板
举报原因:
原因补充:

(最多只允许输入30个字)