C 之函数模板
创始人
2025-07-08 19:40:26
0

为什么需要模板

相信写过Java的童鞋们都知道泛型编程,在C++中与之对应的就是模板。

模板是一种对类型进行参数化的工具,通常有两种形式:函数模板和类模板。

模板是一些为多种类型而编写的函数和类,而且这些类型都没有指定。当使用模板的时候,你只需要把所希望的类型作为一个(显式或者隐式的)实参传递给模板。 另外,由于模板是语言本身所具有的特性,所以它完全支持类型检查和作用域。使用模板的目的就是能够让程序员编写与类型无关的代码,尽可能地减少重复代码。

众所周知,C++是一门强类型的静态语言。在声明变量、函数和大多数其他类型的实体的时候,C++要求我们使用指定的类型。 然而,对于许多代码,除了类型不同之外,其余的代码看起来都是相同的。例如我们需要实现一个交换两个变量的函数,为了通用性, 这个交换变量的函数不能固定两个变量的类型,这就使得模版横空出世。。。

在C++标准库中,几乎所有的代码都是模板代码,可以说没有C++模板就没有STL。

模板函数

首先我们看下函数模板的格式:

template  
返回类型 函数名(参数列表)
{
    函数体
}

或者使用class关键字也可:

template   
返回类型 函数名(参数列表)
{
    函数体
}

为什么会有两种不同的格式呢?这是因为鉴于历史的原因,你可能还会使用class取代typename,来定义类型参数。 在C++语言的演化过程中,关键字typename的出现相对较晚一些;在它之前,关键字class是引入类型参数的唯一方式,并一直作为有效方式保留下来。 但是更加标准的格式是使用typename关键字。

例如我们使用模板定义了返回较大值的模板函数:

template 
const T& max_fun(const T& a,const T& b){
    return a >= b? a:b;
}

下面我们调用一下我们定义的模板函数max_fun:

int main(int argc, char* argv[]) {
    // 都是int类型 ok
    int max = max_fun(10,10);
    // 都是double类型 ok
    int max = max_fun(10,10);
    // 一个int类型,一个double类型 编译不通过
    int max = max_fun(10,11.0);
    std::cout << "max:" << max << std::endl;
    return 0;
}

在上面的例子中我们发现函数max_fun(10,11.0)报错了,无法编译通过,这是为什么呢?因为我们定义的模板函数max_fun只有一个参数类型, 但是max_fun(10,11.0)却传了两个不同的参数类型,二载函数模板中是不允许进行自动类型转换的,因此报错,有两种方式可以解决这个报错:

  • 一是对实参进行强制类型转换,使它们可以互相匹配:
max_fun(10,static_cast(11.0));
  • 二是显式指定(或者限定)T的类型:
max_fun(10,11.0);

重点:在函数模板实参演绎的过程中,是不允许进行自动类型转换的。

重载函数模板

模板函数在使用时编译器回自动实现实例化,只要使用函数模板,(编译器)会自动地引发这样一个实例化过程,因此程序员并不需要额外地请求模板的实例化。

和普通函数一样,函数模板也可以被重载。就是说,相同的函数名称可以根据不同的函数参数具有不同的函数定义; 于是,当使用函数名称进行函数调用的时候,C++编译器必须决定究竟要调用哪个候选函数。

一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。 对于非模板函数和同名的函数模板,如果其他条件都是相同的话,那么在调用的时候,重载解析过程通常会调用非模板函数,而不会从该模板产生出一个实例。

下面我们通过一个小例子来了解下重载函数模板:

#include 
#include 

template 
const T& max_fun(const T& a,const T& b){
std::cout << "模板类型max_fun:"<< std::endl;
return a >= b? a:b;
}

const int& max_fun(const int& a,const int& b){
std::cout << "int 类型max_fun:"<< std::endl;
return a >= b? a:b;
}

int main(int argc, char* argv[]) {
// 都是double类型 匹配到模板函数max_fun
//    int max = max_fun(10.0,11.0);
// 都是int类型 匹配到 普通函数max_fun
//    int max = max_fun(10,10);
// 一个char类型,一个double类型 匹配到普通函数max_fun
int max = max_fun('a',11.0);
std::cout << "max:" << max << std::endl;
return 0;
}

在上面的例子main函数中我们多次调用了函数max_fun,那么怎么区分是调用了模板函数max_fun还是调用了重载的普通函数max_fun呢?

有一条规则是这样的:

一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。对于非模板函数和同名的函数模板,如果其他条件都是相同的话,那么在调用的时候,重载解析过程通常会调用非模板函数,而不会从该模板产生出一个实例。

因此在上面的例子中我们可以很容易地看出第17行调用的是模板函数max_fun,因为没有参数是double类型的max_fun被重载。 但在第19行因为有一个参数是int类型的重载函数max_fun,因此这一行调用的是普通重载函数max_fun。

那么在第21行也是调用了int类型的重载函数max_fun,这是为什么呢?

这是因为模板是不允许自动类型转化的,但普通函数可以进行自动类型转换,所以第21行调用的是int类型的重载函数max_fun(‘a’和11.0都被转化为int)。

函数重载应该牢记一条首要规则:函数的所有重载版本的声明都应该位于该函数被调用的位置之前。

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...