模板与泛型编程

时间:2021-12-28 04:19:35

模板分为函数模板和类模板。

函数模板:一个函数模板就像一个公式,可以用来生成针对特定类型的函数版本。模板定义以关键字template开始,后跟一个模板参数列表。模板参数列表时一个以逗号分割的一个后多个模板参数的列表(不能为空)。用小于号和大于号包围起来。例如:

template <typename T>

int compare(const T&V1,const T&V2)

{

  if(v1<v2) return -1;

  if(v2<v1) return 1;

  return 0;

}

模板类型参数

上例中,compare函数有一个模板类型参数。一般来说,我们可以将类型参数看做类型说明符,就想内置类型或类类型说明符一样使用。特别的是,类型参数可以用来指定返回类型或函数参数的参数类型,以及在函数体内用于变量声明或类型转换:

template <typename T>T foo(T* p)

{  

  T Tmp=*p;

  //...

  return tmp;

}

注意,类型参数前必须使用template或者class关键字,在这里这两个关键字是完全相同的,二者可以互换。

非类型模板参数

一个非类型模板参数表示一个值而非一个类型。我们通过一个特定的类型名而非关键字class或template来指定非类型参数。

例如:

template<unsigned N,unsigned M>

int compare(const char(&p1)[N],const char(&p2)[M])

{

  return strcmp(p1,p2);

}

当我们调用这个版本的compare函数时

compare("hi","mom");

编译器就会使用字面常量的大小来代替N和M,从而实例化模板。编译器会在字符串字面常量的末尾插入一个空字符作为终结符,因此编译器会实例化出下列版本的compare函数

compare(const char (&p1)[3],const char (&p2)[4])

绑定到非类型整型参数的实参必须是一个常量表达式。绑定到指针或者引用非类型参数的实参必须具有静态的生存期。我们不能用一个普通(非static)局部变量或动态对象作为指针或引非类型模板参数的实参。

inline 和constexpr的函数模板

如同非函数模板一样,函数模板可以声明为inline或者constexpr。例如:

template<typename T>inline T min(const T&,const T&);

位置不可变更。

类模板

template<typename T>class B

{

  public:

    typedef T value_type;

    typedef typename vector<T>::size_type;

    Blob();

    Blob(initializer_list<T>i1;

    size_type size()const{

      return data->size();

    }

    bool empty()const {

      return data->empty();

    }

    void push_back(const T&t){

      data->push_back(t);

    }

    void push_back(T&&t){

      data->push_back(move(t));

    }

    void pop_back();

    T&back();

    T&operator[](size_type i);

  private:

    shared_ptr<vector<T>>data;

    void check(size_type i,const string &msg)const;

}