1.非类型的模板类形参
对于函数模板与类模板,模板参数并不局限于类型或者适配器、指针(迭代器),普通值也可以作为模板参数。在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定。但是在这里,我们面对的是这些细节是值,而不是类型,当要使用基于值的模板时,必须显式地指定这些值,才能够对模板进行实例化。
比如可以这样:
template<class T,size_t MAXSIZE>
size_t是一个unsigned类型数,它的作用是保证储存内存中对象的大小,该类型定义在cstddef头文件中。这种定义在《STL源码剖析》中有出现。
当然也可以是普通的整型 比如:
template<typename T,int SIZE = 10> //不止可以有非类型形参,还可以为它设定默认值
class Test
{
// 全设为public类型,纯粹为了方便实现
public:
Test();
Test(T);
Test(const Test &);
T T_array[SIZE];
};
int main()
{
Test<int,20> T1;
Test<double> T2;
}
如上代码所示,模板参数有两个,一个是顺序表中存储数据的类型,另一个就是非类型的类模板参数,用于指定当前顺序表所能存储最大数据的个数。
2.非类型的模板函数形参
除了模板类可以有非类型的模板参数,模板函数也是可以有非类型模板参数。
using namespace std;
template <class T, int value = 20>
T&& add(const T& x)
{
return x + value;
}
int main()
{
cout << add<int>(5) << endl;
cout << add<int, 30>(5) << endl;
return 0;
}
3.非类型模板参数的限制
非类型模板参数是有限制的,通常而言,它们可以是常整数(包括枚举值)或者指向外部链接对象的指针,浮点数和类对象是不允许作为非类型模板参数的,但是很好的是,浮点型指针是可以的:
using namespace std;
template <class T, double value = 20.0>
T&& add(const T& x)
{
return x + value;
}
int main()
{
cout << add<int>(5) << endl;
cout << add<int, 30>(5) << endl;
return 0;
}
如果这样会出现如下错误:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2672 “add”: 未找到匹配的重载函数
错误 C2783 “T &&add(const T &)”: 未能为“value”推导 模板 参数
错误 C2993 “double”: 非类型模板参数“value”的类型非法
错误 C2993 “double”: 非类型模板参数“value”的类型非法
错误 C2672 “add”: 未找到匹配的重载函数
另外,你也不能使用全局类型指针作为模板参数:
比如:
using namespace std;
enum {a = 10};
template <class T, int *value = &a>
T&& add(const T& x)
{
return x + *value;
}
int main()
{
int *value_1 = 15;
cout << add<int>(5) << endl;
cout << add<int, value_1>(5) << endl;
return 0;
}
但是可以用全局函数指针作为模板参数
比如:
// 定义一个foreach函数模板,对数组的每一个元素进行某种操作
// 具体操作由模板的函数指针参数指定
template<typename T, void (*f)(T &v)>
void foreach(T array[], unsigned size)
{
for (unsigned i = 0; i < size; ++i) f(array[i]);
}
// 三个函数模板用来定义对数组元素的操作
template<typename T>
void inc(T &v) {++v;}
template<typename T>
void dec(T &v) {--v;}
template<typename T>
void print(T &v) {std::cout << ' ' << v;}
int main()
{
int array[] = {1, 2, 3, 4, 5, 6, 7, 8};
using namespace std;
foreach<int, print<int> >(array, 8);
cout << endl;
foreach<int, inc<int> >(array, 8);
foreach<int, print<int> >(array, 8);
cout << endl;
foreach<int, dec<int> >(array, 8);
foreach<int, print<int> >(array, 8);
cout << endl;
return 0;
}
上例中,foreach定义为一个函数模板,其第二个模板参数是一个函数指针。由于模板参数必须在编译时给定,所以这个foreach函数实现 了“静态回调”。另有一个值得注意的是,第二个模板参数void(f)(Tv)的定义中用到第一个模板参数T。这是合法的,在模板参数列表中,所声明 模板参数可立即用于定义随后的模板参数。在本例中,void (f)(Tv)约束指针型模板参数f所指函数只能接受与前一模板参数类型相同的指针参数,随后所定义的三个函数模板都是要对数据元素进行的操作,分别 是对元素值加1、减1以及打印。在main函数中则调用foreach函数模板,静态绑定对数组每个元素分别加1、减1以及打印。