模板参数:
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在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;
};
对于向下调整,和向上调整的时候,我们就用仿函数,如果当我们传入的是指针他就会生成关于指针的比较的对象,如果不这样做,对象里的比较只能是具体的对象(内置类型,自定义类型),不能是指针。