泛型编程

16.1.5. 非类型模板形参

模板形参不必都是类型。本节将介绍函数模板使用的非类型形参。在介绍了类模板实现的更多内容之后,第 16.4.2 节将介绍类模板的非类型形参。在调用函数时非类型形参将用值代替,值的类型在模板形参表中指定。例如,下面的函数模板声明了 array_init 是一个含有一个类型模板形参和一个非类型模板形参的函数模板。函数本身接受一个形参,该形参是数组的引用(第 7.2.4节):

//initialize elements of an array to zero

template<class T, size_t N> void array_init(T (&parm)[N])

{

for(size_t i = 0; i != N; ++i) {

parm[i]= 0;

}

}

模板非类型形参是模板定义内部的常量值,在需要常量表达式的时候,可使用非类型形参(例如,像这里所做的一样)指定数组的长度。

790

当调用 array_init 时,编译器从数组实参计算非类型形参的值:

intx[42];

doubley[10];

array_init(x);// instantiates array_init(int(&)[42]

array_init(y);// instantiates array_init(double(&)[10]

编译器将为 array_init 调用中用到的每种数组实例化一个 array_init

版本。对于上面的程序,编译器将实例化 array_init 的两个版本:第一个实例

的形参绑定到 int[42],另一个实例中的形参绑定到 double[10]。

类型等价性与非类型形参

对模板的非类型形参而言,求值结果相同的表达式将认为是等价的。下面的

两个 array_init 调用引用的是相同的实例—— array_init<int,42>:

intx[42];

constint sz = 40;

inty[sz + 2];

array_init(x);// instantiates array_init(int(&)[42])

array_init(y);// equivalent instantiation

Exercises Section 16.1.5

Exercise

16.15:

编写可以确定数组长度的函数模板。

Exercise

16.16:

将第 7.2.4 节的 printValues 函数重新编写为可用于

打印不同长度数组内容的函数模板。

16.1.6. 编写泛型程序

编写模板时,代码不可能针对特定类型,但模板代码总是要对将使用的类型

做一些假设。例如,虽然 compare 函数从技术上说任意类型都是有效的,但实

际上,实例化的版本可能是非法的。

791

产生的程序是否合法,取决于函数中使用的操作以及所用类型支持的操作。

compare函数有三条语句:

if(v1 < v2) return -1; // < on two objects of type T

if(v2 < v1) return 1; // < on two objects of type T

return0; // return int; not dependent on T

前两条语句包含隐式依赖于形参类型的代码,if 测试对形参使用 < 操作

符,直到编译器看见 compare 调用并且 T 绑定到一个实际类型时,才知道形参

的类型,使用哪个 < 操作符完全取决于实参类型。

如果用不支持 < 操作符的对象调用 compare,则该调用将是无效的:

Sales_itemitem1, item2;

//error: no < on Sales_item

cout<< compare(item1, item2) << endl;

程序会出错。Sales_item 类型没有定义 < 操作符,所以该程序不能编译。在函数模板内部完成的操作限制了可用于实例化该函数的类型。程序员的责任是,保证用作函数实参的类型实际上支持所用的任意操作,以及保证在模板使用哪些操作的环境中那些操作运行正常。

编写独立于类型的代码

编写良好泛型代码的技巧超出了本书的范围,但是,有个一般原则值得注意。

编写模板代码时,对实参类型的要求尽可能少是很有益

的。

虽然简单,但它说明了编写泛型代码的两个重要原则:

• 模板的形参是 const 引用。

792

• 函数体中的测试只用 < 比较。

通过将形参设为 const 引用,就可以允许使用不允许复制的类型。大多数类型(包括内置类型和我们已使用过的除 IO 类型之外的所有标准库的类型)都允许复制。但是,也有不允许复制的类类型。将形参设为const 引用,保证这种类型可以用于 compare 函数,而且,如果有比较大的对象调用 compare,则这个设计还可以使函数运行得更快。一些读者可能认为使用 < 和 > 操作符两者进行比较会更加自然:

//expected comparison

if(v1 < v2) return -1;

if(v1 > v2) return 1;

return0;

但是,将代码编写为

//expected comparison

if(v1 < v2) return -1;

if(v2 < v1) return 1; // equivalent to v1 > v2

return0;

可以减少对可用于 compare 函数的类型的要求,这些类型必须支持 <,但不必

支持 >。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值