模板参数:
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
template<class T,int n=10> //T为模板参数,n为非模板参数
class aa
{
private:T[n] data;
};int main(){aa<int, 100>;return 0;}
注意:
1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2. 非类型的模板参数必须在编译期就能确认结果。
特化:
函数模板的特化步骤:
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
前面三个点都非常简单,第四个点就非常让人头大。
比如我们我们要写这个模板的特化怎么写
template<class T>
void func(const T& data)//实际上换成指针为int* const data//是指针不能修改
{cout << typeid(data).name() << endl;
}
我们要这样写:
template<>
void func<int*>(int* const& data) //const放在*之后表示指针本身不能被修改
{cout << typeid(data).name() << endl;
}
如果对c++语法掌握不是很好的话一般都不知道怎么写。 一般用特化我们函数不会用特化。
类模板特化:
类模板的特化和函数模板的特化差不多
template<class T >
class cl
{
public:cl(){cout << "template<class T > " << endl;}
};template<>//全特化
class cl<int*>
{
public:cl(){cout<<"template<>//全特化"<<endl;}
};
除了全特化还有偏特化
偏特化:
任何针对模版参数进一步进行条件限制设计的特化版本。比如对于以下模板类:
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};
这样搞的模板就叫偏特化。
因此我们可以通过仿函数和偏特化的特性来写一个比大小功能。
比如我们在设计一个优先级队列时,就可以这样写:
template<class T>
struct less
{less() = default;bool operator()(const T& d1, const T& d2){return d1 < d2;}
};
template<class T>
struct less<T*>
{less() = default;bool operator()(T* d1, T* d2){return *d1 < *d2;}
};template<class T>
struct mygreater
{mygreater()=default;bool operator()(const T& d1, const T& d2){return d1 > d2;}
};
template<class T>
struct mygreater<T*>
{mygreater() = default;bool operator()(T* d1, T* d2){return *d1 > *d2;}};template< class T, class Container = vector<T>, class func=less<T>>
class priority_queue
{
public:priority_queue()=default;void push(const T& data){_con.push_back(data);Adjust_Up(_con.size()-1);}void pop(){_con.erase(_con.begin());Adjust_Down(0);}T& top(){return _con[0];}bool empty(){return _con.empty();}//向下调整void Adjust_Down(size_t father){func f1;size_t child= father * 2+1;while (child < _con.size()){if (child + 1 < _con.size() && f1(_con[child] , _con[child + 1])){child++;}if (!f1(_con[child] , _con[father])){swap(_con[child], _con[father]);father = child;child = father * 2 + 1;}else{break;}}}//向上调整void Adjust_Up(size_t child){func f1;size_t father = (child - 1) / 2;while (child > 0){if (!f1(_con[child] , _con[father])){swap(_con[child], _con[father]);child = father;father = (child - 1) / 2;}else{break;}}}private:Container _con;
};
对于向下调整,和向上调整的时候,我们就用仿函数,如果当我们传入的是指针他就会生成关于指针的比较的对象,如果不这样做,对象里的比较只能是具体的对象(内置类型,自定义类型),不能是指针。