函数模板是通用的函数描述,其使用泛型来定义函数。其实就是有些操作,如果撇开具体的变量的数据类型,其操作是一样的如果我们将这些操作写成一个模板,在调用不同变量的时候就设定好变量类型就可了,后续的操作基本都是一个流程了。

比如我要对两个变量进行交换,那么不管是int型、double型还是long型或者类或者结构体啥的,我都可以这样实现:

T A = AAAAA;
T B = SB;
T temp = A;
A = B;
B = tem;

这里的T就是数据类型的,不管是什么数据类型,只要可以进行如上操作的,都可以用这个模板来做。

1、函数模板定义

函数模板的定义基本上固定的:

template <typename T>    
void aiZuoNiNa(T a)
{
    
}

其中,template是函数模板的关键字,关键字typename是声明该函数模板的泛型类型,可以用class来替代(C++98前没有typename,所以用class),这两个关键字和尖括号是必须的,typename之后的T可以任意写,只要符合C++命名规则即可,很多人会写做T。

需要注意的是,在定义函数模板的时候是不会创建任何函数的,只是在告诉编译器在调用模板函数的时候该如何定义函数并调用,也就是说如果定义了模板函数,但是从未调用过的话,是不会生成相应的函数的,在程序中使用了定义好的函数模板,那么编译器将检查使用的参数类型,然后根据类型来生成相应函数(就如同我们手写了一个函数一样)。所以即使定义函数模板只有一份,如果调用了两次且数据变量不同的话,编译器会生成两份独立的函数在可执行程序中,也就是说函数模板不会缩短可执行程序,最终的可执行程序也不会包含函数模板,但是会包含调用两次函数模板后编译器所生成的两个独立的函数。

函数模板一般是放在头文件中的。

并不是模板函数的所有参数都得是泛型,可以不要泛型,或者包含其它类型:

template <typename T>
void aiZuoNiNa(T a)
{ } template <typename T>
void aiZuoNiNa(T a, int b)
{ } template <typename T>
void aiZuoNiNa()
{ }

2、模板重载

上面一个例子涉及到函数模板的重载,函数模板的重载与普通函数重载一样,重载函数模板的时候,需要满足函数名相同、参数列表不同函数重载特点即可。

3、函数模板的局限性

这个要怎么说呢,应该说是某些情况不适合简单抽象化或者简单模板化,才导致了函数模板的局限性,比如比较两个变量的大小,对于int、float等数据类型可以实现模板化,但是如果是一个结构体或者一个类、或者一个数组等,在不重载比较操作符号(<、>、==)的时候显然不能这样比较吧。

4、显式具体化

因为有些情况可能不能直接简单的用函数模板,所以才会提供一个具体化函数定义(称为显式具体化,explicit specialization),其中包含所需要的代码,在编译器找到与调用函数匹配的具体化定义后就不再寻找模板函数了。也就是显示具体化函数优先级大于函数模板。C++98的具体化方法规定:

1、对于给定的函数名,可以有非模板函数、模板函数、显示具体化模板函数以及它们的重载;

2、显式具体化的原型和定义应以template<>开头,并通过名称来指定类型;

3、具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

第一条有重载的意味,第二条指出显示具体化的格式,第三条指出当存在多个函数的时候,编译器寻找顺序是非模板函数>具体化模板函数>模板函数。在调用模板函数指定数据类型的时候编译器是会生成一个对应的函数实例,这个函数是不在代码中可见的,故而这种实例化是隐式的,而显示具体化则是在代码里定义的:

// 函数模板
template <typename T>
void jiaoJiRen(T a, T b)
{ }
//显式具体化
template<> void jiaoJiRen<char>(char a, char b)
{ }

5、实例化和具体化

一开始是只有隐式实例化,显示实例化是现在的C++才有的,显式实例化需要声明所需的数据类型(用<>指示数据类型),并在声明前面添加关键字template:

template void jiaoJiRen(int a, int b);

显式具体化是要求编译器在调用的时候不要按照函数模板中的方式来生成函数定义,而要用显式具体化的函数:

//方式一
template<> void jiaoJiRen<char>(char a, char b)
{ }
//方式二
template<> void jiaoJiRen(char a, char b)
{ }

显式具体化和显式实例化的区别:

1、具体化函数声明前

2、显式具体化除了声明还有函数定义,显式实例化只需要做函数声明即可。

3、在同个文件(或者转换单元)中使用同一种类型的显示实例化和显式具体化会出错。

函数模板这一块大致就记录这一些,我觉得暂时够用即可,毕竟是一个工具,目前就是挖的很深,没有使用的余地的话,很快就遗忘,个人的一点感受,之前看设计模式的时候觉得都记住了,一段时间后都模糊了,然后自己昨天写完一个小软件的时候才意识到自己其实用到了单例模式,再去查下单例模式,才知道我用的这个叫懒汉方式。所以有点感想,对于工具的一种学习方法是在实践中使用它,故而有句很装逼的话:

无他,但手熟尔。

C++基础--函数模板的更多相关文章

  1. C++进阶-1-模板基础(函数模板、类模板)

    C++进阶 模板 1.1 函数模板 1 #include<iostream> 2 using namespace std; 3 4 // 模板 5 6 // 模板的简单实例 7 // 要求 ...

  2. Template 基础篇-函数模板(待看

    Template 基础篇-函数模板 Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分. Template ...

  3. C++ 函数模板基础知识

    为什么要引入模板:为了避免代码重复,程序员可以编写脱离数据类型通用模板. 模板的分类:函数模板 + 类模板 注意:模板的声明或定义只能在全局,命名空间或类范围内进行.不能在函数内进行,比如不能在mai ...

  4. [C++基础]那些容易被混淆的概念:函数/数组指针-指针函数/数组,类/函数模板-模板类/函数

    函数指针-指针函数 函数指针的重点是指针.表示的是一个指针,它指向的是一个函数.eg: int (*pf)(); 指针函数的重点是函数.表示的是一个函数,它的返回值是指针.eg: int* fun() ...

  5. 【C++编程基础】(1)—— 函数原型声明、函数模板、引用、const 常引用、const 常量指针

    一.函数原型声明: 1.函数声明告诉编译器函数的名称,和如何调用函数(返回类型和参数):函数定义提供了函数的实际主体. 2.强制性的:在C++中,如果函数调用的位置在函数定义之前,则要求在函数调用之前 ...

  6. 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型

    比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...

  7. [Reprint] C++函数模板与类模板实例解析

    这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下   本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...

  8. c++函数模板---3

    原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 模板从大体上,可以分为两种:函数模板和类模板.函数模板是算法库的基础,类模板是建立标准库容器和迭代器的基 ...

  9. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

随机推荐

  1. php 等于不等于 一个感叹号两个等于号

    $a == $b 等于 TRUE,如果 $a 等于 $b. $a === $b 全等 TRUE,如果 $a 等于 $b,并且它们的类型也相同.(PHP 4 引进) $a != $b 不等 TRUE,如 ...

  2. Maven项目- Servlet的抽取和优化 java.lang.NoSuchMethodException 的解决方法

    优化servlet,减少servlet的数量,便于开发与维护.现在是一个功能一个Servlet,将其优化为一个模块一个Servlet,BaseServlet的抽取和优化,相当于在数据库中一张表对应一个 ...

  3. Day9 - K - Yue Fei's Battle HDU - 5136

    Yue Fei is one of the most famous military general in Chinese history.He led Southern Song army in t ...

  4. 手写MQ框架(四)-使用netty改造梳理

    一.背景 书接上文手写MQ框架(三)-客户端实现,前面通过web的形式实现了mq的服务端和客户端,现在计划使用netty来改造一下.前段时间学习了一下netty的使用(https://www.w3cs ...

  5. 软件环境常识 --dev sit uat

    DEV环境:DEV顾名思义就是develop,即代码开发的环境. SIT环境:System Integration Test系统集成测试,开发人员自己测试流程是否走通. UAT环境:User Acce ...

  6. MyEclipse插件github安装使用

    MyEclipse插件github安装使用   网络上的介绍一堆堆的,但是自己尝试了下,发现问题很多,就动手做个教程. 大纲 1.git客户端安装 2.ssh配置 3.egit安装配置 4.参考资料 ...

  7. leetcode236 Lowest Common Ancestor of a Binary Tree

    """ Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in ...

  8. NULL判斷符

    Null 传导运算符 编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在.比如,要读取message.body.user.firstName,安全的写法是写成下面这样. const ...

  9. jmeter抓取cnode网站token值

    前置条件:已经登录 1.线程组下面先添加HTTP信息头管理器 1.1 jmeter向服务器发送http请求时,需要验证 cookie的等设置信息给到服务器去识别,因此,在发送请求前,我们一般会把相关需 ...

  10. Java笔记--常用类

    1.String类: --使用Unicode字符编码,一个字符占两个字节: --String类是一个final类,代表不可变的字符序列: --字符串是不可变的,一个字符串对象一旦被配置,其内容是不可变 ...