一、为啥需要模板

防止相同功能的重复实现

二、函数模板

1、模板函数的定义

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

上述代码就是个最简单的函数模板

template关键字表示模板,<>中的typename用来表示模板参数,模板参数名字是T。函数体中指向operator>,所以T必须支持operator>

在这里typename可以用class来替换,但是不能用struct来替换

2、模板函数的使用

int main(int argc, char const *argv[])
{int a=Max(10, 20);double b=Max(3.4, 5.6);string s=Max("1234", "5678");cout<<a<<","<<b<<","<<s<<endl;return 0;
}

上述代码中,Max被调用了三次,每次分别用int,double、string作为具体类型,来代替模板参数。用具体类型替代模板参数的过程叫实例化。每次实例化都会产生不同的模板函数实例,所以针对三种类型的每一种,Max都被编译了一次

如果使用了一个不支持operator>的类作为模板参数,那么编译时会报错

test one, two;
Max(one, two);

test是一个自定义不支持operator>的类。

因此可知,当一个函数模板被编译时,编译过程是这样的:1、查看模板代码本身是否有语法错误。2、实例化时,查看是否所有调用都有效。

上述两点导致函数模板在编译时,需要查看函数模板的定义,因此,一般将函数模板的实现也放在头文件的内部

这一点也和普通的函数不一样,普通函数只需要给出声明即可通过编译,但是函数模板在实例化时需要查看内部的实现是否都有效,要给出模板的定义

因为模板代码编译的时候会根据不同的模板参数实例化出不同的代码,所以,要保证模板参数支持具体的函数调用。当以不同的模板参数实例化函数模板,从而调用不同的函数,便是所谓的编译期多态。

3、函数模板的实参推断

当调用Max时,会给Max传参,编译器会根据传入实参的类型对模板参数的类型T进行推断,当传入的时两个int变量,编译器会自动推断模板参数T的类型是int,double和string类型同理。模板的类型参数可以用来指定类型或者返回值的类型,以及在函数体内部进行变量的定义

此外,模板参数不允许进行隐式类型转换,当进行如下调用时,不允许将double转为int,因此编译器提示出现匹配错误

Max(10, 20.2);

解决该错误的方式有三种:

tip1:使用static_cast将int转double或者double转int

Max(static_cast<double>(10), 20.2);

tip2:显示指定T的类型为double或者int

Max<double>(10, 20.2);
Max<int>(10, 20.2);

tip3:添加一个新的模板参数

template <typename T1, typename T2>
const T2& Max(const T1 &a, const T2 &b)
{return a>b?a:b;
}
Max(10.2, 20);

在编译tip3中的代码时,会出现警告

之所以出现问题是因为:实例化Max时,函数的返回值类型有可能和T2不同,上述代码中,返回值类型是const int&,但是返回的有可能是a,也有可能是b,如果返回的是a且a的绑定变量的类型是double,那么当函数返回时,就会出现如下类型转换

const T1 tmp=T2;
const T2 &res=tmp;

上述转换在一般情况下没问题,但是因为tmp在函数内部,是个局部临时变量,函数作用域结束后就无效了,所以不能当做返回值让const T2的引用绑定,所以就会出现上面的警告,关于const与引用见博客https://blog.csdn.net/Master_Cui/article/details/106353580

解决办法就是将返回值的类型变成const T1或者const T2

template <typename T1, typename T2>
const T2 Max(const T1 &a, const T2 &b)
{return a>b?a:b;
}

上述代码的问题就在于当实例化一个Max函数时,返回值有可能被隐式转化

或者直接加个返回值模板参数用来指定返回值

template <typename T1, typename T2, typename RT>
const RT Max(const T1 &a, const T2 &b)
{return a>b?a:b;
}

这种办法带来的问题就是需要显示指定模板参数RT,因为不能对函数模板的返回值进行模板实参推断,所以调用Max时很麻烦

Max<int, double, int>(10, 20.2);

必须得按顺序显示指定模板参数的类型

此时如果还调用Max(10, 20.2);编译就无法通过,因为RT的类型没有指定

为了简单一些,可以将RT放在最前面

template < typename RT,typename T1, typename T2>
const RT Max(const T1 &a, const T2 &b)
{return a>b?a:b;
}
Max<int>(10, 20.2);

这样在实例化函数时,只需要指定返回值RT的类型即可,而不需要指定所有的模板参数

4、函数模板的重载

函数模板也可以重载。当出现重载时,调用原则如下:当一个非模板函数和一个模板函数重名且该模板函数可以实例化为该非模板函数,那么在调用时,会调用非模板函数,而不会从模板函数中产生一个实例

int mymax(const int& a, const int &b)
{cout<<__func__<<"in func"<<endl;return a>b?a:b;
}template <typename T>
const T mymax(const T& a, const T &b)
{cout<<__func__<<"in template"<<endl;return a>b?a:b;
}int main(int argc, char const *argv[])
{mymax(10, 20);mymax<>(10.1, 20.2);return 0;
}

第17行中,尖括号中没有指定任何类型,意味着编译器需要调用模板版本的mymax并进行实参推断

参考

《C++ Template》

《C++ Primer》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++知识点55——函数模板相关推荐

  1. 55.函数模板指针匹配(模板自动匹配*多的)

    1 #include <iostream> 2 using namespace std; 3 4 //模板自动匹配*多的 5 template <class T> 6 void ...

  2. C++知识点62——模板实参推断与函数模板的特化

    一.函数指针与模板实参推断 可以用函数模板初始化一个函数指针或给一个函数指针赋值 示例 template <typename T> int comp(const T &a, con ...

  3. 函数模板与类模板知识点总结

    一.函数模板 template <typename T> T max (T a, T b){return a>b ? a : b; } 编译器编译到max(i1,i2)时,会根据模板 ...

  4. c++模板---1(模板概念,利用模板实现数组排序,函数模板调用规则)

    什么叫泛型编程?1. 参数类型化. 2. 模板 模板概念 c++提供了函数模板,所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表.这个通用函数就成为函数模 ...

  5. C++ 实验2:函数重载、函数模板、简单类的定义和实现

    1.函数重载编程 编写重载函数add(),实现对int型,double型,Complex型数据的加法.在main()函数中定义不同类型 数据,调用测试. #include <iostream&g ...

  6. VS2017 函数模板和类模板的声明、定义和使用

    模板的声明.定义分为两种. 1 将模板的声明和定义都放在头文件中,在主程序的文件中包含此头文件即可 2 将模板的声明和定义分开编写. 在<C++ primer>教材中,将模板的声明和定义分 ...

  7. isEqualTo函数模板久久不能通过,到底是小媛掉发过少,还是发量太多,种种谜团围绕在本题周围。让我们跟随Jine一起探索谜团背后的悬疑。

    原题目如下: 请为判断函数isEqualTo编写一个简单的函数模板,isEqualTo函数利用等号运算符(==)判断两个同类型的参数是否相等,如果相等则返回true:反之返回false.在主函数中,利 ...

  8. C++设计模式由浅入深(二)—— 类模板和函数模板

    二.类和函数模板 C++的模板编程特性是一个又大又复杂的话题,有许多著作专门传授这种特性和技巧.在本书中,我们会用到许多C++中的高级泛型编程特性.那么我们该如何去理解贯穿次数中的这些语言结构呢?本章 ...

  9. C++程序设计(三)—— 函数和函数模板

    一.函数的参数及其传递方式 C++的函数传递有两种传递方式:传值和伟引用.传值分为传"对象值"和"对象地址值","对象值"是指对象的数据成员 ...

最新文章

  1. MindSpore基本原理
  2. java各种包的用途
  3. Android在线更新安装包,Android在线更新下载方案
  4. STM32工作笔记0010---认识GPIO IO端口
  5. python中的模块调用_Python中模块互相调用的例子
  6. excel生成多个sheet .net
  7. 如何使用JS实现页面内容随机显示
  8. excel服务器2010网站,勤哲Excel服务器2010企业版(完整安装包)
  9. 稳压芯片TPS54531的设计和分析
  10. MongoDB数据库练习题
  11. R语言检测异常值的几个案例
  12. Googler在中国的“幸福”生活
  13. 微信小程序请求java后台 springmvc 获取json
  14. django实现上传头像和头像展示功能
  15. DataGrid 嵌套应用
  16. Weex Android 动画揭秘
  17. html弹出式登录窗口(DIV悬浮窗口)实现
  18. cocos2d-x 使用Box2d制作的台球游戏
  19. 独立后台2.0全新版本微信红包封面抽奖流量主小程序 裂变快 收益高
  20. 新概念英语学习的方法

热门文章

  1. Android实用代码七段(五)
  2. 项目ITP(二) 二维码 拿起你的手机装一装,扫一扫 【每日一搏】
  3. Redis常见面试题总结
  4. R - history
  5. 根据gtf格式的基因注释文件得到人所有基因的染色体坐标
  6. Python_note2 基本图形绘制+turtle库使用
  7. html2canvas文字重叠(手机端)
  8. PhpStorm+PhpStudy开发环境的配置
  9. C语言:一个涉及指针函数返回值与printf乱码、内存堆栈的经典案例
  10. 汤森路透为何一定要卖掉SCI?