简单掌握C++中的函数模板

1.函数模板的声明和模板函数的生成
1.1函数模板的声明
函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。
函数模板的声明形式为:
template<typename 数据类型参数标识符>

<返回类型><函数名>(参数表)
{
  函数体
}

其中,template是定义模板函数的关键字;template后面的尖括号不能省略;typename(或class)是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符。这样,在以后定义的这个函数中,凡希望根据实参数据类型来确定数据类型的变量,都可以用数据类型参数标识符来说明,从而使这个变量可以适应不同的数据类型。例如:

template<typename T>
T fuc(T x, int y)
{
  T x;
  //……
}

如果主调函数中有以下语句:

double d;
int a;
fuc(d,a);

则系统将用实参d的数据类型double去代替函数模板中的T生成函数:

double fuc(double x,int y)
{
  double x;
  //……
}

函数模板只是声明了一个函数的描述即模板,不是一个可以直接执行的函数,只有根据实际情况用实参的数据类型代替类型参数标识符之后,才能产生真正的函数。
关键字typename也可以使用关键字class,这时数据类型参数标识符就可以使用所有的C++数据类型。
1.2.模板函数的生成
函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。例如:
使用中应注意的几个问题:
(1)函数模板允许使用多个类型参数,但在template定义部分的每个形参前必须有关键字typename或class,即:
template<class 数据类型参数标识符1,…,class 数据类型参数标识符n>

<返回类型><函数名>(参数表)
{
   函数体
}

(2)在template语句与函数模板定义语句<返回类型>之间不允许有别的语句。如下面的声明是错误的:

template<class T>
int I;
T min(T x,T y)
{
  函数体
}

(3)模板函数类似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。

2 函数模板的异常处理
函数模板中的模板形参可实例化为各种类型,但当实例化模板形参的各模板实参之间不完全一致时,就可能发生错误,如:

template<typename T>
void min(T &x, T &y)
{ return (x<y)?x:y; }
void func(int i, char j)
{
  min(i, i);
  min(j, j);
  min(i, j);
  min(j, i);
}

例子中的后两个调用是错误的,出现错误的原因是,在调用时,编译器按最先遇到的实参的类型隐含地生成一个模板函数,并用它对所有模板函数进行一致性检查,例如对语句

min(i, j);

先遇到的实参i是整型的,编译器就将模板形参解释为整型,此后出现的模板实参j不能解释为整型而产生错误,此时没有隐含的类型转换功能。解决此种异常的方法有两种:
(1)采用强制类型转换,如将语句min(i, j);改写为min(i,int( j));
(2)用非模板函数重载函数模板
方法有两种:
(1)借用函数模板的函数体
此时只声明非模板函数的原型,它的函数体借用函数模板的函数体。如改写上面的例子如下:
template<typename T>

void min(T &x, T &y)
{ return (x<y)?x:y; }
int min(int,int);
void func(int i, char j)
{
  min(i, i);
  min(j, j);
  min(i, j);
  min(j, i);
}

执行该程序就不会出错了,因为重载函数支持数据间的隐式类型转换。
(2)重新定义函数体
就像一般的重载函数一样,重新定义一个完整的非模板函数,它所带的参数可以随意。C++中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:
• 寻找一个参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用是一个错误的调用。
• 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。
• 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。
•若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。

3.小例子

#include <iostream>
#include <string>
using namespace std; 

template<class T> void swap(T *x, T *y){//函数的模板,只要能使用等号赋值类型都可以用这个模板互换
  T temp = *x;
  *x = *y;
  *y = temp;
} 

void main(){
  int i = 9, j = 5;
  float k = 9.2, l = 5.6;
  swap(&i, &j);//交换整形
  swap(&k, &l);//交换浮点型
  cout<<"i = "<<i<<" , j = "<<j<<endl;
  cout<<"k = "<<k<<" , l = "<<l<<endl;
}
时间: 2016-04-06

C++函数模板与类模板实例解析

本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++的STL(标准模板库). 模板(template)是泛型编程的基础,一个模板就是一个创建类或函数的蓝图或公式.例如,当使用一个vector这样的泛型类型或者find这样的泛型函数

C++中函数模板的用法详细解析

定义 我们知道函数的重载可以实现一个函数名多用,将功能相同或者类似函数用同一个名来定义.这样可以简化函数的调用形式,但是程序中,仍然需要分别定义每一个函数. C++提供的函数模板可以更加简化这个过程. 所谓函数模板实际上是建立一个通用函数,其涵涵素类型额形参类型不具体指定,用一个虚拟的类型来代表,这个通用函数就称为函数模板. 凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需要在模板中定义一次即可.在调用函数时,系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能

深入解析C++中的函数模板和函数的默认参数

C++函数模板 我们知道,数据或数值可以通过函数参数传递,在函数定义时它们是未知的,只有在发生函数调用时才能确定其值.这就是数据的参数化. 其实,数据类型也可以通过参数来传递,在函数定义是可以不指明具体的数据类型,当发生函数调用时,编译器可以根据传入的参数自动确定数据类型.这就是数据类型参数化. 所谓函数模板,实际上是建立一个通用函数,其返回值类型和形参类型不具体指定,用一个虚拟的类型来代替(实际上是用一个标识符来占位).这个通用函数就称为函数模板(Function Template).凡是函数

解析C++中不能重载为友元函数的四个运算符

C++规定有四个运算符 =, ->, [], ()不可以是全局域中的重载(即不能重载为友员函数),这是为什么呢?现在先说说赋值运算符"="的重载C++规定赋值运算符"="只能重载为类的非静态成员函数,而不可以重载为类的友元函数.不能重载为类的静态成员应该比较容易理解,因为静态成员函数是属于整个类的,不是属于某个对象的,它只能去操作类静态数据成员.而赋值运算符"="是基于对象操作的.那么为什么赋值运算符不可以重载为类的友元函数?像同样都是双目

解析WordPress中的post_class与get_post_class函数

post_class() post_class 是 WordPress 内置的一个用于显示文章 class 名称的函数,该函数通常会为每一篇文章生成独一无二的 clss 值,如果你需要制作你自己的主题,而且还需要一点个性的话,那你最好驻足一下,使用该函数并配合灵活的 css 代码,我们可以制作出个性化十足的 WordPress 博客. post_class 函数描述 该函数通常会为每一篇文章生成独一无二的 clss 值,可以很方便使用于文章所在的节点中. 函数使用 向其他的诸如 header_i

深入解析WordPress中加载模板的get_template_part函数

最近研究官方主题 Twenty Eleven ,有一些东西网上现成的中文资料不好找,在博客里记载下来,算是分享,也算是备忘,wordpress 3.0 以后就开始便有了get_template_part() 这个函数 ,应该是为文章呈现形式提供更为多样化的选择而给出的新功能. Twenty Eleven 中 实例如下: Twenty Eleven index.php 文件  行:21 <?php if ( have_posts() ) : ?> <?php twentyeleven_co

解析VC中创建DLL,导出全局变量,函数和类的深入分析

一.创建DLL1.在VC中新建一个Win32空项目MathLib:2.添加预编译头文件stdafx.h,定义导入导出控制符号: 复制代码 代码如下: //stdafx.h#pragma once#define MATHLIB_EXPORT 3.添加包含要导出的全局变量,函数和类的头文件MathLib.h: 复制代码 代码如下: //MathLib.h #pragma once #ifdef MATHLIB_EXPORT #define MATHLIBAPI __declspec(dllexpor

C++中函数的默认参数详细解析

使用方法:(1)在函数声明或定义时,直接对参数赋值,该参数就是默认参数.(2)在函数调用时,省略部分或全部参数,这时就会使用默认参数进行代替. 注意事项:(1)一般在声明函数是设置默认参数. 如果在函数声明和定义函数时都设置了默认参数,则以函数声明的默认参数为准. 复制代码 代码如下: #include<iostream>using namespace std;int main(){ double add(double a=3.2,double b=9.6);//在函数声明时设置默认参数 co

C++ Template 基础篇(一):函数模板详解

Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分. 为什么要有泛型编程 C++是一门强类型语言,所以无法做到像动态语言(python javascript)那样子,编写一段通用的逻辑,可以把任意类型的变量传进去处理.泛型编程弥补了这个缺点,通过把通用逻辑设计为模板,摆脱了类型的限制,提供了继承机制以外的另一种抽象机制,极大地提升了代码的可重用性. 注意:模板定义本身不参与编译,而是编译器根据模板的用户使

解析C++中构造函数的默认参数和构造函数的重载

C++构造函数的默认参数 和普通函数一样,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值. [例] #include <iostream> using namespace std; class Box { public : Box(int h=10,int w=10,int len=10); //在声明构造函数时指定默认参数 int volume( ); private : int height; int width; int l

Python中的默认参数详解

文章的主题 不要使用可变对象作为函数的默认参数例如 list,dict,因为def是一个可执行语句,只有def执行的时候才会计算默认默认参数的值,所以使用默认参数会造成函数执行的时候一直在使用同一个对象,引起bug. 基本原理 在 Python 源码中,我们使用def来定义函数或者方法.在其他语言中,类似的东西往往只是一一个语法声明关键字,但def却是一个可执行的指令.Python代码执行的时候先会使用 compile 将其编译成 PyCodeObject. PyCodeObject 本质上依然