模版类定义
直接先说一下模版类的定义:
template <模版类型1,模版类型2...>
class 类名
{
内容
}
一个小示例如下:
template<class T>
class A
{
private:
T data;
public:
A(T value) :data(value) {};
T GetData() { return this->data; }//模版函数,返回类型为T的值
};
模版类成员函数
以上的模版函数是在类的内部定义的,如果我们要定义一个定义在类外的类模版成员函数的话,我们应该将这样的类模版成员函数定义在类的.h文件一起,定义方法如下:
template <模版类型1,模版类型2...>
返回类型 类名<模版类型1,模版类型2...>::函数名(参数1,参数2)
{
内容
}
以下为一个示例:
template<class T>
class A
{
private:
T data;
public:
A(T value) :data(value) {};
T GetData() { return this->data; }//模版函数,返回类型为T的值
T Test() const;
};
template<class T>
T A<T>::Test() const
{
cout << "hello,template class" << endl;
return data;
}
当我们使用如下代码的时候:
A<int> intA(1);
这个时候,类模版会绑定到int类型上,然后使用int类型来实例化出特定的类,比如上面的代码就会实例化出与下面等价的类:
template<>
class A<int>
{
private:
int data;
public:
A(int value) :data(value) {};
int GetData() { return this->data; }//模版函数,返回类型为T的值
int Test() const ;
};
template<>
int A<int>::Test() const
{
cout << "hello,template class" << endl;
return data;
}
当编译器从我们的类模版A中实例化出一个类的时候,它会重写A模版,将摸板参数T的每一个实例都替换成给定的模版实参
如果一个成员函数没有被使用,它就不会被实例化。成员函数只有我们使用的时候才会实例化,当然,我们可以自己特化针对特定类型的成员函数
模版类代码区域内和代码区域外的不同模板名使用方法
在类模版自己的作用域下和在类外的模版使用方法是不同的
我写一个例子,还是如上的代码,模版类A,在类的内部写一个如下成员函数:
A Test()
{
A a1= *this;
return a1;
}
这个成员函数是不用写成返回值为A<T>
类型的,而只需要写成A
,但若是在类外定义这个函数,就必须写成刚才上面所说的格式:
template<class T>
A<T> A<T>::Test()
{
A a1 = *this;
return a1;
}
我们就必须使用完整的A<T>
作为返回值
不过在函数的内部,由于我们已经进入了类的作用域,所以在定义a1的时候,无需重复模版实参。原因如下:
在类的作用域内,如果我们不提供模版实参,则编译器将默认我们的类型与成员实例化所用类型一致
因此,a1的定义实际上如下:
A<T> a1 = *this ;
模版类型别名
我们可以定义一个typedef
来引用一个实例化的类:
typedef A<int> intA ;
但是我们没办法定义一个typedef
引用一个模版,即无法定义一个typedef
引用A<T>
但是,新标准允许我们为类模版定义一个类型别名:
template <class> using twin_p=pair<T,T>;
twin<string> stringPair;//stringPair是一个pair<string,string>类型数据
模版类的static成员
与所有类一样,类模版也可以定义static
成员:
template<class T>
class A
{
private:
T data;
static int static_value;
public:
A(T value) :data(value) {};
T GetData() { return this->data; }//模版函数,返回类型为T的值
static int GetValue()
{
return static_value;
}
};
在上面的代码里面,A是一个类模版,它有一个名为static_value
的static成员变量。这代表每一个A的实例都有一个名为static_value
的static
数据成员实例
即,对任何给定类型X,都有一个A<X>::static_value
,所有A<x>
共享同一个static成员
由于每一个模版实例都有其独有的static成员,所有static的定义也要定义为模版:
template<class T>
int A<T>::static_value = 5; //定义并且初始化static_value
同样,我们也可以通过实例类直接访问具体的static成员:
cout << A<int>::GetValue() << endl; // 5
和其他的成员函数类似,一个static的成员函数和成员变量也只有在使用的时候才会实例化。
模版默认实参
在新标准中,我们可以为函数和模版类提供默认实参,比如如下代码(比较两个数的大小,默认使用标准库 less<T>
函数对象模版 ):
template<calss T,calss F=less<T>>
int compare(const T& v1, const T& v2, F f = F())
{
if (f(v1, v2))return -1;
if (f(v2, v1))return 1;
return 0;
}
我们就将这个less<T>
绑定到F的默认参数上,当我们不使用第三个参数的时候,它就默认使用less<T>
来进行比较:
int i = compare(1, 5); //使用less,i=-1
data<int> d1(1), d2(2);
bool j = compare(d1, d2, compareData);//自己写的比较函数模版
可以看到,我们可以自己写比较函数,也可以直接用默认的比较函数,标准库里的很多东西都是如此,套路深。
最后
观察如下代码:
template<typename T = int>
class data
{
private:
T value;
public:
data(T v) :value(v) {};
};
data<double> doublueData(3.5);
data<>intData(4); //空<>表示我们希望使用默认类型
我们可以给所有的模版参数都给定默认实参,且如果我们希望使用这些默认实参,我们就跟一个空尖括号对。
~结束