C++深入理解(4)------函数模板以及显式具体化(读书笔记)
2018-02-26 14:57
686 查看
在编程的过程中虽然很少使用到函数模板,但是在底层代码的编写中却有时会用到,下面将详细介绍一下函数模板:
函数模板是一种应用泛型的一种方式,可以定义一个函数,函数的参数和返回值都是可以根据模板而变动的,不用定义多个重载函数来实现因为参数不同而功能相同的问题。
如下面的交换函数,void swap(int &a,int &b){}; 有时候我们会用到int类型,有时候会用到double类型,功能相同的函数却因为参数不同却要重新编写一次,不仅浪费时间,而且非常容易出错,所以使用函数模板就可以避免这种问题。
下面写出模板定义的标准格式:
template <typename T>void swap(T &a,T &b){}或者
template<class T> void swap(T &a,T &b);
这里简单的说下tpyename和class的异同:他们两个在作用上是相同的,都是表示模板类型的关键词,两者在使用上没有任何区别,唯一的区别在与typename可以更清晰的告诉读者是模板类型,而class更绕一点,但是有大量的库使用class这种用法的。
本质上说:模板并不创建任何函数,而是类似一个过程语言,它来告诉编译器怎么去创建一个函数,如需要用int来替换时,就会用int来创建一个函数,而需要用double来替换时,就用double来创建一个函数。因此函数模板并不能缩短函数执行过程, 在执行时仍然需要创建两个函数定义,而最终的代码是不包含任何模板的,只包含模板生成的实际函数。所以使用模板的好处是可以减少手工定义的工作量。
这里额外还要说的一个概念是显式具体化,有时候定义的模板能处理大部分的类型,但是有某些特殊类型需要却与基本的算法不同,这时就要用到显式具体化这种神奇的东西:
其标准的格式是:
template <> void swap<job>(job &a,job &b){.......};
这样可以定义复杂的结构job,当调用以job作为参数的函数时,就优先调用这个显示具体化的函数,如果没有job作为参数的显式具体化,那么还是根据老的模板来定义job函数。
这里需要另外说明的还有一个概念:显式实例化。这个概念比较和显示具体化是两个不同的概念。显示实例化的标准格式 template void swap<int>(int &a,int &b);
通过使用显示实例化这样声明,编译器就知道要穿件一个int类型的函数定义,与之对应的是隐式实例化,只有当遇到swap(a,b),a,b都为int类型时才会创建这个函数定义。而显示实例化却是要穿件另外一种类型的不同算法,前者(显示实例化)是不改变算法只创建函数,而后者则是即改变算法也创建。
概念基本讲完了,说下使用中注意的细节,在使用中常常会遇到这样的问题:
swap(T1 &a, T2 &b){ ... ?type? = a + b; ...} 那么a+b是什么类型呢,因为a可能是int,b可能是double,则a+b为double,其他传入类型又是不同的,这里C++增加了一个关键词decltype,具体使用为decltype(a+b) c=a+b;decltype() 后声明的变量c为与()内部的变量是同一种类型的变量。
还有一种返回值也是不知道type的,如?type? swap(T a,T b);返回值也是不定的,这里可以使用C++新的后置返回类型,具体的格式如下:
template <class T1,class T2>
auto func(T1 x,T2)->decltpye(x+y){}
其中的->表示返回值类型为->后类型相同的类型。
函数模板是一种应用泛型的一种方式,可以定义一个函数,函数的参数和返回值都是可以根据模板而变动的,不用定义多个重载函数来实现因为参数不同而功能相同的问题。
如下面的交换函数,void swap(int &a,int &b){}; 有时候我们会用到int类型,有时候会用到double类型,功能相同的函数却因为参数不同却要重新编写一次,不仅浪费时间,而且非常容易出错,所以使用函数模板就可以避免这种问题。
下面写出模板定义的标准格式:
template <typename T>void swap(T &a,T &b){}或者
template<class T> void swap(T &a,T &b);
这里简单的说下tpyename和class的异同:他们两个在作用上是相同的,都是表示模板类型的关键词,两者在使用上没有任何区别,唯一的区别在与typename可以更清晰的告诉读者是模板类型,而class更绕一点,但是有大量的库使用class这种用法的。
本质上说:模板并不创建任何函数,而是类似一个过程语言,它来告诉编译器怎么去创建一个函数,如需要用int来替换时,就会用int来创建一个函数,而需要用double来替换时,就用double来创建一个函数。因此函数模板并不能缩短函数执行过程, 在执行时仍然需要创建两个函数定义,而最终的代码是不包含任何模板的,只包含模板生成的实际函数。所以使用模板的好处是可以减少手工定义的工作量。
这里额外还要说的一个概念是显式具体化,有时候定义的模板能处理大部分的类型,但是有某些特殊类型需要却与基本的算法不同,这时就要用到显式具体化这种神奇的东西:
其标准的格式是:
template <> void swap<job>(job &a,job &b){.......};
这样可以定义复杂的结构job,当调用以job作为参数的函数时,就优先调用这个显示具体化的函数,如果没有job作为参数的显式具体化,那么还是根据老的模板来定义job函数。
这里需要另外说明的还有一个概念:显式实例化。这个概念比较和显示具体化是两个不同的概念。显示实例化的标准格式 template void swap<int>(int &a,int &b);
通过使用显示实例化这样声明,编译器就知道要穿件一个int类型的函数定义,与之对应的是隐式实例化,只有当遇到swap(a,b),a,b都为int类型时才会创建这个函数定义。而显示实例化却是要穿件另外一种类型的不同算法,前者(显示实例化)是不改变算法只创建函数,而后者则是即改变算法也创建。
概念基本讲完了,说下使用中注意的细节,在使用中常常会遇到这样的问题:
swap(T1 &a, T2 &b){ ... ?type? = a + b; ...} 那么a+b是什么类型呢,因为a可能是int,b可能是double,则a+b为double,其他传入类型又是不同的,这里C++增加了一个关键词decltype,具体使用为decltype(a+b) c=a+b;decltype() 后声明的变量c为与()内部的变量是同一种类型的变量。
还有一种返回值也是不知道type的,如?type? swap(T a,T b);返回值也是不定的,这里可以使用C++新的后置返回类型,具体的格式如下:
template <class T1,class T2>
auto func(T1 x,T2)->decltpye(x+y){}
其中的->表示返回值类型为->后类型相同的类型。
相关文章推荐
- 深入理解C++对象模型-成员函数的本质以及虚函数的实现(非虚继承)
- 【转载】C/C++杂记:深入理解数据成员指针、函数成员指针
- [李景山php] 深入理解PHP内核[读书笔记]--第四章:函数的实现 --函数的调用和执行
- c++多重继承和虚继承及虚函数深入理解
- 深入理解C++中函数参数——传值与传址详解
- C++中的模板比较容易混淆的几个概念:类模板和类成员模板以及函数模板
- 【ThinkingInC++】73、深入理解模板
- C++深入理解虚函数
- [李景山php] 深入理解PHP内核[读书笔记]--第四章:函数的实现 --简介
- 深入理解 C++ 指针(七)---指针和函数的关系
- [李景山php] 深入理解PHP内核[读书笔记]--第四章:函数的实现 --函数的参数
- C++中虚函数的理解,以及简单继承情况下的虚函数的表!
- 深入理解c++中char*与wchar_t*与string以及wstring之间的相互转换 [转]
- [李景山php] 深入理解PHP内核[读书笔记]--第四章:函数的实现 --函数的参数-1
- 深入浅出理解:函数模板与类模板、存在的实际意义以及使用方法,
- [c++ template]非类型的函数模板以及非类型的类的模板
- 关于C以及C++中指针的深入理解
- 【C++】深入理解模板
- C++多态:深入虚函数,理解晚绑定
- [李景山php] 深入理解PHP内核[读书笔记]--第二章:用户代码执行--opcode处理函数查找