C++中函数模板的深入理解
1,函数模板深入理解:
1,编译器从函数模板通过具体类型产生不同的函数;
1,模板就是模子,通过这个模子可以产生很多的实物;
2,函数模板就是编译器用来产生具体函数的模子;
2,编译器会对函数模板进行两次编译:
1,对模板代码本身进行编译;
1,检查函数模板本身有无语法错误等;
2,对参数替换后的代码进行编译;
1,调用函数模板的时候,编译器要根据实际的参数类型得到真正的函数,这个时候编译器会对这个函数进行第二次编译;
2,注意事项:
1,函数模板本身不允许隐式类型转换:
1,自动推导类型时,必须严格匹配;
1,函数模板本身不是函数,它只是产生函数的模子,因此函数模板本身不允许隐式类型转换;
2,显示类型指定时,能够进行隐式类型转换;
1,显示指定类型,就会得到真实的函数,这个时候有可能进行隐式类型转换;
3,函数模板的本质编程实验:
#include <iostream>
#include <string> using namespace std; class Test
{
Test(const Test&);
public:
Test()
{
}
}; template < typename T >
void Swap(T& a, T& b) // 这里编译器显示为: In function 'void Swap(T&, T&)';说明这也是函数,是模板函数;
{
T c = a;
// a = b // 当文件中只有类模板一个参数时,编译器显示:error: expected ';' before 'b';证明了编译器还是会对模板本生进行编译;
a = b;
b = c;
} typedef void(FuncI)(int&, int&); // 定义函数类型,类型名为 FuncI;
typedef void(FuncD)(double&, double&);
typedef void(FuncT)(Test&, Test&); int main()
{
/* pi 和 pd 指向具体函数,但是 pi 和 pd 指向的具体函数是由函数模板具体产生,这里已经产生了函数,不是模板了,这两个函数是两个独立的不同的函数 */
FuncI* pi = Swap; // 定义函数指针,并能编译通过;这里编译器通过函数指针的类型自动推导 T 为 int; 编译器默默做的事有:1,首先进行自动推导;2,产生真正的 Swap() 函数;3,将实际生成的 Swap() 函数地址用于初始化 pi; FuncD* pd = Swap; // 编译器自动推导 T 为 double; /* 证明编译器做了第二次编译 */
FuncT* pt = Swap; // 没有显示声明拷贝构造函数时,编译器自动推导 T 为 Test;
// FuncT* pt = Swap; // 编译器显示:instantiated from here
// error: 'Test::Test(const Test&)' is private
// error: within this context(也就是 Swap 中 T c = a; 语句);
// 这里的编译错误是二次编译时发现的,自动推导 T 为 Test 后,会产生一个 Swap() 函数,接下来会对 Swap() 函数进行编译,接下来就发现 T c = a; 行有问题; cout << "pi = " << reinterpret_cast<void*>(pi) << endl; // 将 pi 这个指针的类型重解释为 void*;打印:0x80487a8;
cout << "pd = " << reinterpret_cast<void*>(pd) << endl; // 打印:0x80487ca;
cout << "pt = " << reinterpret_cast<void*>(pt) << endl; // 没有显示声明拷贝构造函数时,打印:0x8048828;
// cout << "pt = " << reinterpret_cast<void*>(pt) << endl; return ;
}
4,多参数函数模板:
1,函数模板可以定义任意多个不同的类型参数:
1,代码示例:
template < typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
return static_cast<T1>(a + b);
} int r = Add<int, float, double>(0.5, 0.8);
2,仅仅是调用的时候多了几个泛指类型而已;
2,对于多参数函数模板:
1,无法自动推导返回值类型;
1,只有返回值类型必须手工的指定;
2,一般的工程中指定第一个模板参数为返回值类型;
2,可以从左向右部分指定函数类型参数:

1,剩下的参数类型编译器可以自动推导;
3,工程中,将返回值参数作为第一个类型参数;
1,返回值是泛指类型,则将第一个类型参数作为返回值类型;
2,这是工程中手动设置的,并不是编译器自己的行为;
5,多参数函数模板编程实验:
#include <iostream>
#include <string> using namespace std; template
< typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
return static_cast<T1>(a + b);
} int main()
{
// T1 = int, T2 = double, T3 = double
int r1 = Add<int>(0.5, 0.8); // T1 = double, T2 = float, T3 = double
double r2 = Add<double, float>(0.5, 0.8); // T1 = float, T2 = float, T3 = float
float r3 = Add<float, float, float>(0.5, 0.8); cout << "r1 = " << r1 << endl; // r1 = 1
cout << "r2 = " << r2 << endl; // r2 = 1.3
cout << "r3 = " << r3 << endl; // r3 = 1.3 return ;
}
6,当函数重载遇见函数模板会发生什么?
1,见下本文7 中的分析;
7,重载函数模板:
1,函数模板可以像普通函数一样被重载:
1,C++ 编译器优先考虑普通函数;
2,如果函数模板可以产生一个更好的匹配,那么选择模板;
3,可以通过空模板实参列表限定编译器只匹配模板:

8,重载函数模板实例分析:
#include <iostream>
#include <string> using namespace std; template < typename T >
T Max(T a, T b)
{
cout << "T Max(T a, T b)" << endl; return a > b ? a : b;
} int Max(int a, int b) // C++ 中这个函数可以重载上面的模板;
{
cout << "int Max(int a, int b)" << endl; return a > b ? a : b;
} template < typename T >
T Max(T a, T b, T c)
{
cout << "T Max(T a, T b, T c)" << endl; return Max(Max(a, b), c); // 这里是重载的模板;
} int main()
{
int a = ;
int b = ; cout << Max(a, b) << endl; // 普通函数 Max(int, int) cout << Max<>(a, b) << endl; // 函数模板 Max<int>(int, int) cout << Max(3.0, 4.0) << endl; // 函数模板 Max<double>(double,double) cout << Max(5.0, 6.0, 7.0) << endl; // 函数模板 Max<double>(double, double, double) cout << Max('a', ) << endl; // 普通函数 Max(int, int);函数模板是不会进行隐式类型转换的,因此这时不会考虑上述两个模板进行隐式推导,这里直接考虑普通函数并进行隐式类型转换; return ;
}
9,小结:
1,函数模板通过具体类型产生不同的函数;
2,函数模板可以定义任意多个不同的类型参数;
3,函数模板中的返回值类型必须显示指定;
4,函数模板可以像普通函数一样被重载;
C++中函数模板的深入理解的更多相关文章
- 谈谈自己对C语言中函数指针的一些理解 (第一次写博客,有点小兴奋哈)
1.函数指针声明的格式及简单的使用 (1)格式:(返回值)(*函数指针名)(参数列表) 例如:声明一个无参数无返回值的函数指针(void)(*p)(void). (2)将函数指针指向某个无参数无 ...
- 为什么 c++中函数模板和类模板的 声明与定义需要放到一起?
将模板的声明与定义写在一起实在很不优雅.尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义, 然后在main函数里包含.h头文件,这样会报链接错误.why!!!!!!!!!!!!! 这是因为 ...
- C++中函数模板的概念和意义
1,对泛型编程进行学习,泛型编程是实际工程开发中必用的技术,大型公司的通用 库都是采用泛型编程的技术完成的,C++ 中支持泛型编程技术,C++ 中的函数 模板和类模板就是 C++ 中泛型编程技术,本 ...
- 25.C++- 泛型编程之函数模板(详解)
本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数和函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int&am ...
- C++ 函数模板用法
泛型编程概念:不考虑具体数据类型的编程方式: 函数模板: 1.提供一种特殊的函数可用不同类型进行调用: 2.与普通函数很相似,区别是类型可被参数化: template <typename T&g ...
- 一个例子理解c++函数模板的编译
一.例子 template <typename T> inline void callWithMax(const T& a, const T& b){ f(a > b ...
- 如何理解javaSript中函数的参数是按值传递
本文是我基于红宝书<Javascript高级程序设计>中的第四章,4.1.3传递参数小节P70,进一步理解javaSript中函数的参数,当传递的参数是对象时的传递方式. (结合资料的个人 ...
- C++中的函数模板
我们在定义函数时,可以通过定义函数模板,来简化一些功能相同而数据类型不同的函数的定义和调用过程. C++中的函数模板 对于类的声明来说,也有同样的问题.有时,有两个或多个类,其功能是相同的,仅仅是数据 ...
- 深入理解python中函数传递参数是值传递还是引用传递
深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...
随机推荐
- Go语言_包、变量和函数
包.变量和函数 学习 Go 程序的基本结构. Go 作者组编写,Go-zh 小组翻译. https://go-zh.org 包 每个 Go 程序都是由包构成的. 程序从 main 包开始运行. 本程序 ...
- c# UDP分包发送
考虑到UDP的高速和其他协议的复杂性,做了一个依靠时间发送的分包组包重发的UDP库. https://github.com/jinyuttt/UDPTTL.git
- ApacheHttpServer出现启动报错:the requested operation has failed解决办法
转自:https://www.jb51.net/article/21004.htm 原因一:80端口占用 例如IIS,另外就是迅雷.我的apache服务器就是被迅雷害得无法启用! 原因二:软件冲突 装 ...
- Oracle连接远程数据库
我用的事navicat连接工具 方法一: 找到 工具---->环境,OCI环境 选择中间那个(我的是这个,我不确定是不是都一样,可以都试试),选好之后关闭navicat,重新运行navicat ...
- HTML基础 内联样式改进 三毛语录
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- HTML5 arc的例子
demo.html <!DOCTYPE html> <html lang="zh"> <head> <meta charset=" ...
- loj6177 「美团 CodeM 初赛 Round B」送外卖2 最短路+状压dp
题目传送门 https://loj.ac/problem/6177 题解 一直不知道允不允许这样的情况:取了第一的任务的货物后前往配送的时候,顺路取了第二个货物. 然后发现如果不可以这样的话,那么原题 ...
- Java反射初识
反射Class类 Class类是反射的根源,很多很多的类,经过抽象,得出了一个Class类,包括类名,构造方法,属性方法等.得到Class类的对象的三种方式: Object类中的getClass()方 ...
- tmux使用——2019年11月20日16:40:15
1.tmux 命令行的典型使用方式是,打开一个终端窗口(terminal window,以下简称"窗口"),在里面输入命令.用户与计算机的这种临时的交互,称为一次"会话& ...
- markdown解析与着色
markdown解析与着色 简介 最近在调整博客园博客样式,使用markdown发表的博客.这个不要太好用,有道云+markdown简直绝配,可以发在任何支持markdwon的博客网站,样式基本不会走 ...