非类型的模板参数

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以及打印。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值