C++学习笔记:函数模板

6 篇文章 1 订阅

函数模板

C++提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表,是一种对类型进行参数化的工具。这种通用的方式称为模板。模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

C++模板通常有两种形式:函数模板和类模板;这篇文章主要讲函数模板相关知识,函数模板是那些被参数化的函数,它们代表的是一个函数家族。它的表示(即外形)看起来和普通的函数很相似,唯一的区别就是有些函数元素是未确定的,这些元素将在使用时被(编译器)参数化。一个简单的模板函数max如下:

template <typename T>
inline T const& max (T const& a, T const& b) {
    return a < b ? b : a;
}

这个max模板函数中的参数a和b的类型是未确定的,用模板参数T来代替,T可以是很多类型,如int,char,double,甚至是自定义的class等类型,只要它支持operator<,因为a和b需要使用这个运算符来比较大小的。

调用该模板函数时,可以显示的实例化模板:

::max<int>(1, 2);  // inline int const& max (int const& a, int const& b)
::max<>(1.0, 1.2)  //实例化为double const& max (double const&, double const&);

也可以根据实参的类型自动对函数版本进行实例化,自动推导:

::max(1.0, 1.2);   //call max<double>

函数模板重载

模板还可以进行重载,也可以跟非模板函数重载:

template <typename T>
inline T const& max (T const& a, T const& b, T const& c) {
 // 调用两次参数模板
    return max(max(a, b), c); 
}

// 求两个int值的最大值,非模板函数
inline int const& max (int const& a, int const& b) {
    return a < b ? b : a;
}

调用如下:

::max(1.0, 1.2);  // 调用max<double>模板函数
::max(100, 200);  // 调用int重载的非模板函数,优先调用非模板函数
::max<>(100, 200); // 调用max<int>模板函数, 这里显式说明一定要用模板函数,具体使用哪个根据实参类型

顺便提一下,使用::界定符说明调用的是全局的max,因为std中也有一个max,如果直接写max而不是::max ,某些情况下可能会用到std::max,避免产生二义性,直接写成::max。

注意,模板函数是不允许进行自动类型转换;每个T都必须正确地匹配。

::max(1, 1.2);  // 错误

// error: no matching function for call to 'max(int, double)'
// candidate: 'template<class T> T max(T, T)'

如上面代码,我们只定义了max(T, T)模板函数,要求两个形参的类型必须一致,上面我们调用参数一个是int一个是double,按照以前的经验,如果没有模板函数max,只有max(int, int),那么这个调用就会将1.2隐式转为int类型进行比较而不会报错。

模板函数与函数重载

函数重载与函数模板是两个有些相似的概念,函数重载(overloaded),即定义**「函数名相同而形参列表(形参个数或形参类别)不同」的多个函数,这些函数被称为重载函数,重载函数通常「执行的操作非常类似」**(每个函数体内也可以执行不同的动作),如打印不同的输入对象。调用函数时编译器根据实参的类型确定调用哪个重载函数。

void print(const char *ch);
void print(const int *num);
void print(const int *begin, const int *end);
// 传入的实参是字符串,调用打印字符串的print函数
print("good study, day up") 

函数模板提供一个种用来自动生成各种类型函数实例的算法,程序员对于函数接口参数和返回类型中的全部或者部分类型进行参数化(parameterize)而函数体保持不变。

调用函数模板时,编译器(通常)用函数实参来推断模板实参。然后根据实参类型实例化模板函数。

**「函数重载」用于定义功能相似的同名函数,提高函数的易用性;「函数模板」**则用于为实现逻辑一样只是参数类型不同的一类函数提供统一的模板,提高函数编写的效率。

另外,函数模板也可以进行重载。函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。

模板函数

首先模板函数与模板函数不是一个概念,上面我们说的都是函数模板。函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。「将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数」。模板函数的生成就是将函数模板的类型形参实例化的过程。

也就是,在我们编译的时候,编译器内部会自动生成这些模板函数,然后再进行调用,当然,这些都是编译器内部生成的,我们可以不用去了解太深,我们知道这个概念就可以了。

「我们只是定义了一个函数模板,而在调用的时候,内部会自动帮我们生成一个模板函数,然后再执行这个模板函数,得到我们想要的结果」

总结

模板就是方便我们依样画葫芦,由你提供一个整体框架(函数体),再由编译器去完善整个细节。

  1. 函数模板可以像普通函数一样被重载;

  2. C++编译器优先考虑普通函数;

  3. 如果函数模板可以产生一个更好的匹配,则选择模板;

  4. 可以通过空模板实参列表的语法限定编译器只通过模板匹配;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值