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++中函数模板的深入理解的更多相关文章

  1. 谈谈自己对C语言中函数指针的一些理解 (第一次写博客,有点小兴奋哈)

    1.函数指针声明的格式及简单的使用 (1)格式:(返回值)(*函数指针名)(参数列表)    例如:声明一个无参数无返回值的函数指针(void)(*p)(void). (2)将函数指针指向某个无参数无 ...

  2. 为什么 c++中函数模板和类模板的 声明与定义需要放到一起?

    将模板的声明与定义写在一起实在很不优雅.尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义, 然后在main函数里包含.h头文件,这样会报链接错误.why!!!!!!!!!!!!! 这是因为 ...

  3. C++中函数模板的概念和意义

    1,对泛型编程进行学习,泛型编程是实际工程开发中必用的技术,大型公司的通用 库都是采用泛型编程的技术完成的,C++ 中支持泛型编程技术,C++ 中的函数  模板和类模板就是 C++ 中泛型编程技术,本 ...

  4. 25.C++- 泛型编程之函数模板(详解)

    本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数和函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int&am ...

  5. C++ 函数模板用法

    泛型编程概念:不考虑具体数据类型的编程方式: 函数模板: 1.提供一种特殊的函数可用不同类型进行调用: 2.与普通函数很相似,区别是类型可被参数化: template <typename T&g ...

  6. 一个例子理解c++函数模板的编译

    一.例子 template <typename T> inline void callWithMax(const T& a, const T& b){ f(a > b ...

  7. 如何理解javaSript中函数的参数是按值传递

    本文是我基于红宝书<Javascript高级程序设计>中的第四章,4.1.3传递参数小节P70,进一步理解javaSript中函数的参数,当传递的参数是对象时的传递方式. (结合资料的个人 ...

  8. C++中的函数模板

    我们在定义函数时,可以通过定义函数模板,来简化一些功能相同而数据类型不同的函数的定义和调用过程. C++中的函数模板 对于类的声明来说,也有同样的问题.有时,有两个或多个类,其功能是相同的,仅仅是数据 ...

  9. 深入理解python中函数传递参数是值传递还是引用传递

    深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...

随机推荐

  1. k8s ingress路由强制跳转至https设置

    为ingress配置增加注解(annotations):nginx.ingress.kubernetes.io/ssl-redirect: 'true' 就可以实现http强制跳转至https 不过默 ...

  2. JS-02 一元运算符理解

    <script> var i=1; j=i++ + i++; console.log(j); //结果是3 console.log(i); //结果是3 </script> 代 ...

  3. 手动实现一个vue的mvvm,思路解析

    1.解析dom.fragment编译,初始化new watcher 2 ,数据劫持,Object.defineProperty(obj,key,{ configurable:true,// 可以配置 ...

  4. java泛型通配符详解

    前言 泛型带来的好处 泛型中通配符 常用的 T,E,K,V,? ?无界通配符 上界通配符 < ? extends E> 下界通配符 < ? super E> ?和 T 的区别 ...

  5. day19 python模块 json模块 pickle模块

    day19 python   一.序列化模块     序列类型: 列表 字符串 元组 bytes     序列化: 特指字符串和bytes, 就是把其他的数据类型转化成序列的数据类型的过程 dic = ...

  6. find命令进阶(三):xargs

    The xargs command performs an interesting function. It accepts input from standard input and convert ...

  7. visual studio 中gitflow使用

    vs中已集成了git,但是如果想使用gitflow,要去扩展包里面下载 装完后,在右侧面板的"团队资源管理"就会出现gitflow 进行git flow实始化 后就可以进行 各分支 ...

  8. JavaScript的MD5加密

    1.首先要到http://pajhome.org.uk/crypt/md5/下载js文件. 2.在页面文件中添加: <script type="text/javascript" ...

  9. ceph-状态监测-脚本

    http://www.tang-lei.com/2018/06/05/ceph-%E7%8A%B6%E6%80%81%E7%9B%91%E6%B5%8B-%E8%84%9A%E6%9C%AC/ 为了能 ...

  10. LDD3 第13章 USB驱动程序

    通用串行总线(USB)是主机和外围设备之间的一种连接.最新USB规范修订增加了理论上高达480Mbps的高速连接. 从拓扑上看,USB子系统并不是以总线的方式来布置的,它是一颗由几个点对点的连接构建而 ...