一、非类型模版参数
在讲解该概念之前,我们先来思考下面这个问题。假如我们现在想要实现一个静态的栈结构,大小为10,按照之前所学的知识的话应该这么写:
#define N 10
template<class T>
class Stack
{
private:
T a[N];
int _top;
int _capacity;
};
如果我们要开的空间大小为100的话,只需要把#define定义的宏的10改为100即可。看似程序也很灵活,但是解决不了下面这个问题:加入我们现在要开两个静态栈,一个栈的大小为10,另一个大小为100,那么这个程序就不能同时满足上面的两个需求。所以这时候就需要用非类型模版参数来解决这个问题。
那么什么是非类型模版参数呢?首先,模版参数可以分为类型形参和非类型形参。类型形参指出现在模版参数列表中,跟在class或者typename之类的参数类型名称(比如上面代码中的形参T)。而非类型形参就是用一个常量作为类/函数模版的一个参数,在类/函数模版中可将该参数当成常量来使用。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
template<class T, size_t N>
class Stack
{
private:
T a[N];
int _top;
int _capacity;
};
int main()
{
Stack<int, 10> st1; //10
Stack<int, 100> st2; //100
return 0;
}
注意:这里只能传常量,不能传变量。像下面这段代码就是错误的!!!
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
template<class T, size_t N>
class Stack
{
private:
T a[N];
int _top;
int _capacity;
};
int main()
{
int x;
cin >> x;
Stack<int, x> st3; // error
return 0;
}
在C++入门中,我们讲过函数参数可以传缺省值,同理,这里也可以给缺省值,并且规则是一样的,都是从右往左连续给缺省值。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
template<class T = int, size_t N = 1000>
class Stack
{
private:
T a[N];
int _top;
int _capacity;
};
int main()
{
Stack<int, 10> st1; //10
Stack<int, 100> st2; //100
Stack<int> st3; //1000
Stack<> st4; //1000
return 0;
}
注意:浮点数、字符串以及类对象是不允许作为非类型模板参数的!
二、模板的特化
2.1 概念
我们先来看下面这段代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
template<class T>
bool Less(T x, T y)
{
return x < y;
}
int main()
{
cout << Less(1, 2) << endl;
double* p1 = new double(1.1);
double* p2 = new double(2.2);
cout << Less(p1, p2) << endl;
string* p3 = new string("111");
string* p4 = new string("222");
cout << Less(p3, p4) << endl;
return 0;
}
接着我们运行三次这段代码:



可以发现,三次运行结果各不相同。因为我们这里比较的是指针的大小,而在堆上申请的空间是随机的,所以指针的大小就是随机的,因此出现的结果才会不同。所以这里要进行特殊化处理,也就是在原模板的基础上,针对特殊类型所进行的特殊化的实现方式。模板特化分为函数模板特化和类模板特化。
2.2 函数模板特化
函数模板的特化步骤:
1.必须要先有一个基础的函数模板
2.关键字template后面接一对尖括号<>
3.函数名后跟一对尖括号<>,尖括号里面指定需要特化的类型
根据以上步骤,刚才的代码就可以特化成下面的形式:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
//函数模板--参数匹配
template<class T>
bool Less(T x, T y)
{
return x < y;
}
//特化
template<>
bool Less<double*>(double* x, double* y)
{
return *x < *y;
}
template<>
bool Less<string*>(string* x, string* y)
{
return *x < *y;
}
int main()
{
cout << Less(1, 2) << endl;
double* p1 = new double(1.1);
double* p2 = new double(2.2);
cout << Less(p1, p2) << endl;
string* p3 = new string("111");
string* p4 = new string("222");
cout << Less(p3, p4) << endl;
return 0;
}
或许有人一开始就会有疑问,为什么原函数模板用的是传值传参?按理来说,在C++中,传引用传参的效率更高啊,不应该写成 const T& 更好吗?是这样的没错,但是如果真的这么写,程序反而出现问题了(如下图所示)。

那为什么特化不上呢?在原函数模板中,const修饰的是x和y本身,但是在特化的函数模板中,const修饰的并不是指针x和y本身,而是修饰的指针所指向的内容,因此这里要把const放在*的右边。程序如下:
template<class T>
bool Less(const T& x, const T& y)
{
return x < y;
}
//特化
template<>
bool Less<double*>(double* const& x, double* const& y)
{
return *x < *y;
}
2.3 类模板特化
2.3.1 全特化
将模板参数列表中的所有参数都确定化。
template<class T1,class T2>
class Data
{
public:
Data()
{
cout << "Data<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//全特化
template<>
class Data<int, char>
{
public:
Data()
{
cout << "Data<int, char>" << endl;
}
};
2.3.2 偏特化
偏特化有以下两种表现方式:
·部分特化:将模板参数列表中的一部分参数特化
template<class T1,class T2>
class Data
{
public:
Data()
{
cout << "Data<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//偏特化
//特化部分参数
template<class T1>
class Data<T1, char>
{
public:
Data()
{
cout << "Data<T1, char>" << endl;
}
};
·对参数的更进一步限制
template<class T1,class T2>
class Data
{
public:
Data()
{
cout << "Data<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//对参数进一步限制
template<class T1,class T2>
class Data<T1*, T2*>
{
public:
Data()
{
cout << "Data<T1*, T2*>" << endl;
}
};
4万+

被折叠的 条评论
为什么被折叠?



