模板
模板(template)是一个类或者一个函数,以一组类型或/和整数为参数:
template<typename T>
class vector{
public:
//...
int size() const;
private:
int sz;
T* p;
};
template <class T>
int vector<T>::size() const
{
return sz;
}
在模板参数列表中,class表示类型,也可以用typename来表示类型。模板类的成员函数隐含地定义为模板函数,其模板参数与模板类一致。
整数模板参数必须是常量表达式。
template <typename T, int sz>
class Fixed_array{
public:
T a[sz];
//...
int size() const {return sz;};
};
Fixed_array<char, 256> x1; //正确的定义
int var = 256;
Fixed_array<char, var> x2; //错误的定义:非const模板实参
模板参数
当使用模板类时,需要指定模板参数:
vector<int> v1; //正确
vector v2; //错误,模板实参缺失
vector<int, 2> v3; //错误,模板实参过多
vector<2> v4; //错误,要求模板实参为类型
模板函数的模板参数则通常通过函数的实参推断出来:
template<class T>
T find(vector<T>& v,int i)
{
return v[i];
}
vector<int> v1;
vector<double> v2;
//...
int x1 = find(v1,2); //find()的T为int
double x2 = find(v2,2); //find()的T为double
模板实例化
指明了一组特定模板参数的模板版本称为特例(specialization)。
由模板和一组参数生成的特例的过程称为模板实例化(template instantition)。
通常是由编译器从一个模板和一组模板参数生成一个特例,但程序员也可以定义特殊的特例,这通常是因为一般模板不适合一组特殊的模板参数,eg:
template<class T> struct Compare{ //通用比较
bool operator()(const T&a, const T&b)const
{
return a<b;
}
};
template<> struct Compare<const char*>{ //比较C风格的字符串
bool operator()(const char* a,const char* b) const
{
return strcmp(a,b) == 0;
}
};
Compare<int> c1; //通用风格
Compare<const char*>c2; //C风格字符串比较
boo1 b1 = c1(1,2); //使用通用比较
bool v=b2 = c2("asd","dfg"); //使用C风格字符串比较
对于函数,通过重载可以达到大致类似的效果:
template<class T>bool compare(const T&a,const T&b)
{
return a<b;
}
bool compare(cosnt char* a,const char* b) //比较C风格的字符串
{
return strcmp(a,b) == 0;
}
boo1 b3 = compare(2,3); //使用通用比较
bool b4 = compare("asd","fgh"); //使用C风格字符串比较
模板的分离编译(即,头文件中只有声明,而唯一的定义置于.cpp文件中)不具备可移植性,因此,如果模板需要在多个.cpp文件中使用的话,应该将其完整定义置于头文件中。
模板成员类型
模板的成员可以是类型,也可以不是类型(例如数据成员和成员函数)。
这意味着,一般很难分辨一个成员名是类型还是非类型。处于语言技术上的原因,编译器必须要知道这方面的信息,因此有时我们必须将相关的信息告知编译器。
为此,我们需要使用关键字typename。
eg
template<class T> struct Vec{
typedef T value_type; //一个成员类型
static int const; //一个数据类型
//...
};
template<class T> void my_fct(Vec<T>& v)
{
int x = Vec<T>::count; //默认情况下,编译器假定成员名引用的是非类型成员
v.count = 7; //引用非类型成员的更简单的办法
typename Vec<T>::value_type xx = x; //这里需要typename
//..
}