模板与泛型编程
模板分为函数模板和类模板。
函数模板:一个函数模板就像一个公式,可以用来生成针对特定类型的函数版本。模板定义以关键字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;
}