
标题: C++模板 - 2(函数模板2-类型参数推断) [打印本页]
作者: upup22you 时间: 2024-6-18 22:06 标题: C++模板 - 2(函数模板2-类型参数推断)
好了,我们继续学习函数模板。对了,上文的那个函数模板长什么样子来着?几天不见有点忘了。复制内容到剪贴板
代码:
template <typename T>
T max(T a, T b) {
return b < a ? a : b;
}
如果max是个普通函数,那它的名字就叫max(因为它定义在全局空间,所以更准确的名字应该是::max)。不过它现在升级为函数模板了,那我们应该如何称呼它呢?对于函数模板,类型参数也是它的名字的一部分,所以正确的名称是max<T>,当然在最终生成的代码中不会有这个名字,有的只会是max<int>这样的类型实例化后的名称。
如果每次调用都需要带上类型参数,如max<double>(3.1, 5.2),这也有点太low了吧?没事,你还有一个可以永远值得信赖的朋友,编译器,它对代码的类型了如指掌,如果你没有指定类型参数的类型(通常情况下你都不会主动给出类型的,“懒惰是美德!”这个对程序员来说绝对是无比正确的),那它就会试着从传入参数的类型推断出T的类型。max(1, 2),OK,编译器说了,我知道了,T为int。max(3.1, 5.2),too easy,T是double。复制内容到剪贴板
代码:
int i = 3;
int& i_r = i;
const int j = 7;
max(i_r, j);
这次呢?编译器说你是故意使坏吧?一个是int&,另一个是const int,你让我选哪个?这里的答案是int。注意max的定义,参数是以传值的形式传入的(想一下你用一个int&或const int来给一个int变量赋值时会发生什么?它们只是把对应变量里面的值复制了一份)。编译器在对值语义传递的参数类型进行推断时,对于传入参数的const,引用&都会忽略掉,如果是数组或函数,会转化为对应的指针类型。复制内容到剪贴板
代码:
int array[6]; // T为int*
void foo(int a); // T为void(*)(int)
嗯,不错,编译器的推断基本上符合我们的预期。代码运行一切正常。突然有一天,你想改进一下max,我们可是努力工作的程序员嘛,T可以是任何类型,只要类型满足T在函数中的使用约束。int之类的内置类型每次调用时复制一份参数内容无关紧要,如果是个拥有大量存储资源的对象,每次调用都需要创建一个局部的新对象,然后复制一份参数给它,这个有点太浪费了,使用引用可以避免不必要的复制。好,说改就改。复制内容到剪贴板
代码:
template <typename T>
T max(const T& a, const T& b) {
return b < a ? a : b;
}
没有了参数复制,直接引用外部对象,运行效率瞬间提高N倍。不过,可能在某一天,很不幸你的代码编译出错了。原因是这里参数是以引用的形式传入的,编译器在对引用语义传递的参数类型进行推断时,会应用另一套规则,跟之前的值语义不尽相同,这可能会导致很多问题,举一个最简单的一个例子复制内容到剪贴板
代码:
int array[6]; // T为int(&)[6],这个时候数组的长度也是类型的一部分
max(array[5], array[6]),在值语义时编译没有问题,两个都被推断为int*,T类型没有歧义,但是在引用语义时一个是int(&)[5],另一个是int(&)[6],两个类型不一样,编译器无法最终拍板,而且int*可以比较大小,可以作为返回值返回,数组类型可没有内置的比较大小操作。这个有点复杂,以后咱们再深入学习。刚开始咱们不能搞这么沉重的话题。这里想说的就是函数模板的类型参数不需要你给出,编译器会利用实际传入的参数进行推断,大多数情况下跟你想的是一样的。还是那句话,快乐学习,轻松编程。
欢迎光临 SiS001! Board - [第一会所 关闭注册] (http://23.225.255.94/forum/) |
Powered by Discuz! 7.2 |