《c++ primer》第16章 模板与泛型编程

来源:互联网 发布:java runnable thread 编辑:程序博客网 时间:2024/04/29 03:42

泛型编程就是独立于任何特定类型的方式进行编码。模板是泛型编程的基础。使用模板无需了解模板的定义。依赖于编译时的多态性或参数式多态性

模板的定义

  1. 函数模板定义
  2. template <typename T>int compare(const T &v1,const T &v2){      if(v1<v2) return -1;      if(v2>v1) return 1;      return 0;}

    模板形参表<typename T>
  3. 类模板
    template <class Type>class Queue{ public:    Queue();    Type &front();     ......}

  4. 非类型模板形参
    template<class T,size_t N>void array_init(T (&parm)[N]){     for(size_t i = 0;i!= N;++i)    {        parm[i] = 0;    }}
    在需要常量表达式的时候,可使用非类型形参指定数组长度
    int x[42];array_init(x);   //初始化  array_init(int (&)[42])

  5. 编写模板代码的时候,对实参类型要求尽可能的少是有益的

模板的实例化

  1. 多个类型的实参完全匹配
    template<typename T>int compare(const T& v1,const T& v2){    ......}int main(){     short si;     compare(si,1024);//error 应该同为相同的类型     return 0;}

  2. (稍加注意)类型的实参形参受限转换:const转换,数组或函数到指针转换。
    template<T> T fobj(T,T);template<T> T fref(const T&,const T&);string s1("a value");const string s2("another value");fobj(s1,s2);   //全部变换为非const类型fref(s1,s2);    //转换为const类型int a[10];int b[42];fobj(a,b);   //可以将数组名转换为指针fref(a,b);   //错误,不能将数组名转换为指针

模板编译类型

  1. 当编译器看到模板的时候,并不立即产生代码,只有用到模板的时候,如调用了函数模板或定义了类模板的对象的时候,编译器才产生特定类型的模板实例。
  2. 区别:调用函数的时候,编译器只需要看到函数的声明。类似,定义类类型的对象,类定义必须可以使用,但成员函数的定义不一定要存在。所以将类定义和函数声明放在头文件中,函数和成员函数的定义放在源文件中。模板不同,要进行实例化,编译器必须能够访问定义模板的源代码
  3. 标准c++为编译模板定义了两种类型。不同之处在于如何使用源文件中的定义。
  4. 包含模型:编译器必须看到所有模板的定义,所以在头文件中添加#include指示。编译效率比较差,会有多个实例化,优化来避免
  5. 分别编译模型:export关键字。指明给定的定义可能需要在其他文件中产生实例化。在一个文件中,一个模板只能定义为导出一次。头文件中类或函数不能声明为export,一般在源文件中的函数定义以及类的定义源文件中声明为export。

类模板成员

  1. 何时实例化类和成员?类模板成员只有为程序所用才进行初始化。如果某函数从未使用过,则不会实例化该成员函数
  2. (有意思)类模板中的友元声明:a将友元关系授予明确的指定的类或函数   b授予对友元所有类型的访问权限   c只授予对类模板或函数模板的特定实例的访问权的友元声明
    //情况btemplate <class Type>class Bar{   template<class T>friend class Fool;   template<class T>friend void templ_fcn1(const T&);}//情况c,只有给定与bar实例有相同模板实参的Foo2和fcn2,才可以为友元template <class T>class Foo2;template <class T>class templ_fcn2(const T&)template <class Type>class Bar{   friend class Foo2<Type>;   friend void <Type>templ_fcn2(const Type&);}

  3. 成员模板(定义两个模板形参)
    template<class Type>class Queue{public:     template<class It>     Queue(It beg,It end):head(0),tail(0){       ......}      ......}
    //外部定义的时候,必须含有两个模板形参template<class T>template<class Iter>void Queue<T>::assign(Iter beg,Iter end){     destroy();     copy_elems(beg,end);}
  4. static成员,每个实例化都有自己的static成员
    //分享同一个static成员Foo<int> fi,fi2,fi3;//单独的static成员Foo<string>fs

  5. Queue与QueueItem完整定义
    #include <iostream>// declaration that Queue is a template needed for friend declaration in QueueItemtemplate <class Type> class Queue;// function template declaration must precede friend declaration in QueueItemtemplate <class T> std::ostream& operator<<(std::ostream&, const Queue<T>&);template <class Type> class QueueItem {    friend class Queue<Type>;    // . . .    // needs access to item and next    friend std::ostream&     operator<< <Type> (std::ostream&, const Queue<Type>&);    // . . .// private class: no public section    QueueItem(const Type &t): item(t), next(0) { }    Type item;           // value stored in this element    QueueItem *next;     // pointer to next element in the Queue};template <class Type> class Queue {    // needs access to head     friend std::ostream&     operator<< <Type> (std::ostream&, const Queue<Type>&);public:    // empty Queue    Queue(): head(0), tail(0) { }public:    // construct a Queue from a pair of iterators on some sequence    template <class It>     Queue(It beg, It end):           head(0), tail(0) { copy_elems(beg, end); }    // . . .    // copy control to manage pointers to QueueItems in the Queue    Queue(const Queue &Q): head(0), tail(0)                                   { copy_elems(Q); }    Queue& operator=(const Queue&);    ~Queue() { destroy(); }    // replace current Queue by contents delimited by a pair of iterators    template <class Iter> void assign(Iter, Iter);    // rest of Queue class as before    // return element from head of Queue    // unchecked operation: front on an empty Queue is undefined    Type& front()             { return head->item; }    const Type &front() const { return head->item; }    void push(const Type &);      // add element to back of Queue    void pop();                   // remove element from head of Queue    bool empty() const {          // true if no elements in the Queue        return head == 0;    }private:    QueueItem<Type> *head;         // pointer to first element in Queue    QueueItem<Type> *tail;         // pointer to last element in Queue    // utility functions used by copy constructor, assignment, and destructor    void destroy();                // delete all the elements    void copy_elems(const Queue&); // copy elements from parameterprivate:    // version of copy to be used by assign to copy elements from iterator range    template <class Iter> void copy_elems(Iter, Iter); };
    需要注意的是:输出函数不是成员函数,而是两个类的友元;  QueueItem中声明了一对一的友元Queue;  Queue中有成员模板的定义