C++之模板
2016-06-21 16:53
239 查看
如何编写一个通用的加法函数呢?
1、使用函数重载,针对每个所需要的相同行为的不同类型重新实现它。
缺点:只要有新的类型出现,就要重新添加对应函数;
除类型外,所有函数的函数体都相同,代码的复用率不高;
如果函数只是返回值类型不同,函数重载不能解决;
一个方法有问题,所有的方法都有问题,不好维护。
2、使用公共基类,将通用的代码放在公共的基础类里面。
缺点:借助公共基类来编写通用代码,将会失去类型检测的优点;
对于以后实现的许多类,都必须继承自某个特定的基类,代码维护更加困难。
3、使用特殊的预处理程序
#define ADD(a,b) ((a)+(b))
缺点:不是函数,不进行参数类型检测,安全性不高;
还有什么办法吗?
4、----------------------------泛型编程-------------------------------------------
泛型编程:编写与类型无关的逻辑代码,是代码复用的一种手段。模板是泛型编程的基础。
C++模板
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int
型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。
注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
模板:分为函数模板和类模板。
函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生的函数的特定类型版本。
函数模板的格式:
template<typename Param1,typename Param2,.........class Param>
返回值类型 函数名(参数列表)
{
........................
}
定义模板关键字
template<typename T>
T Add(T left,T right)
{
return (left+right)
}
typename是用来定义模板参数关键字,也可以使用class.建议尽量使用typename.
模板函数也可以定义为inline函数。
注意:inline关键字必须放在模板形参表之后,返回值之前,不能放在template之前。
模板是一个蓝图,它本身不是类或者函数, 编译器用模板产生指定你或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。
注意:模板被编译了两次:
实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号;
在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些参数调用
实参推演:
模板形参名字只能在模板形参之后到模板声明或 定义的末尾之间使用,遵循名字屏蔽的规则。
模板形参的名字在同一模板形参列表中只能使用一次。
所有模板形参前面必须加上class或者typename关键字修饰。
注意:在函数模板的内部不能指定缺省的模板实参。
【模板函数特化】
有时候并不总是能够写出对所有可能被实例化的类型都最适合的模板,在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者并不能编译,或者做一些错误的事情。
注意特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明吧,然后使用该特化版本的源文件包含该头文件。
类模板:
知识点:
模板参数(实现容器适配器)、模板的模板参数(容器适配器)、非类型的类模板参数(浮点数和类对象是不允许作为非类型模板参数的)
非类型形参:
1、非类型模板形参:模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。
2、非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。
3、 非类型[b]模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。[/b]但是double &,double *,对象的引用或指针是正确的。
4、 调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。
5 、注意:任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。
6、 全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参。
7 、sizeof表达式的结果是一个常量表达式,也能用作非类型模板形参的实参。
8 、当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有int b,这时A<int, b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。
9 、非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int, 3>(2)这样就把非类型形参a设置为整数3。显示模板实参在后面介绍。
10、 非类型模板形参的形参和实参间所允许的转换
1、允许从数组到指针,从函数到指针的转换。如:template <int *a> class A{}; int b[1]; A<b> m;即数组到指针的转换
2、const修饰符的转换。如:template<const int *a> class A{}; int b; A<&b> m; 即从int *到const int *的转换。
3、提升转换。如:template<int a> class A{}; const short b=2; A<b> m; 即从short到int 的提升转换
4、整值转换。如:template<unsigned int a> class A{}; A<3> m; 即从int 到unsigned int的转换。
5、常规转换。
类模板的特化:分为全特化和偏特化
(偏特化:并不仅仅是指特殊部分的参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本)
模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。
模板的分离编译:
总结而已!
1、使用函数重载,针对每个所需要的相同行为的不同类型重新实现它。
缺点:只要有新的类型出现,就要重新添加对应函数;
除类型外,所有函数的函数体都相同,代码的复用率不高;
如果函数只是返回值类型不同,函数重载不能解决;
一个方法有问题,所有的方法都有问题,不好维护。
2、使用公共基类,将通用的代码放在公共的基础类里面。
缺点:借助公共基类来编写通用代码,将会失去类型检测的优点;
对于以后实现的许多类,都必须继承自某个特定的基类,代码维护更加困难。
3、使用特殊的预处理程序
#define ADD(a,b) ((a)+(b))
缺点:不是函数,不进行参数类型检测,安全性不高;
还有什么办法吗?
4、----------------------------泛型编程-------------------------------------------
泛型编程:编写与类型无关的逻辑代码,是代码复用的一种手段。模板是泛型编程的基础。
C++模板
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int
型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。
注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
模板:分为函数模板和类模板。
函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生的函数的特定类型版本。
函数模板的格式:
template<typename Param1,typename Param2,.........class Param>
返回值类型 函数名(参数列表)
{
........................
}
定义模板关键字
template<typename T>
T Add(T left,T right)
{
return (left+right)
}
typename是用来定义模板参数关键字,也可以使用class.建议尽量使用typename.
模板函数也可以定义为inline函数。
注意:inline关键字必须放在模板形参表之后,返回值之前,不能放在template之前。
模板是一个蓝图,它本身不是类或者函数, 编译器用模板产生指定你或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。
注意:模板被编译了两次:
实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号;
在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些参数调用
实参推演:
模板形参名字只能在模板形参之后到模板声明或 定义的末尾之间使用,遵循名字屏蔽的规则。
模板形参的名字在同一模板形参列表中只能使用一次。
所有模板形参前面必须加上class或者typename关键字修饰。
注意:在函数模板的内部不能指定缺省的模板实参。
【模板函数特化】
有时候并不总是能够写出对所有可能被实例化的类型都最适合的模板,在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者并不能编译,或者做一些错误的事情。
注意特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明吧,然后使用该特化版本的源文件包含该头文件。
类模板:
知识点:
模板参数(实现容器适配器)、模板的模板参数(容器适配器)、非类型的类模板参数(浮点数和类对象是不允许作为非类型模板参数的)
非类型形参:
1、非类型模板形参:模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。
2、非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。
3、 非类型[b]模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。[/b]但是double &,double *,对象的引用或指针是正确的。
4、 调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。
5 、注意:任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。
6、 全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参。
7 、sizeof表达式的结果是一个常量表达式,也能用作非类型模板形参的实参。
8 、当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有int b,这时A<int, b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。
9 、非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int, 3>(2)这样就把非类型形参a设置为整数3。显示模板实参在后面介绍。
10、 非类型模板形参的形参和实参间所允许的转换
1、允许从数组到指针,从函数到指针的转换。如:template <int *a> class A{}; int b[1]; A<b> m;即数组到指针的转换
2、const修饰符的转换。如:template<const int *a> class A{}; int b; A<&b> m; 即从int *到const int *的转换。
3、提升转换。如:template<int a> class A{}; const short b=2; A<b> m; 即从short到int 的提升转换
4、整值转换。如:template<unsigned int a> class A{}; A<3> m; 即从int 到unsigned int的转换。
5、常规转换。
类模板的特化:分为全特化和偏特化
(偏特化:并不仅仅是指特殊部分的参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本)
模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。
模板的分离编译:
总结而已!
相关文章推荐
- C002-CPP-Luhn公式
- 标准C++中的string类的用法总结
- C002-CPP-函数集合
- Peeking Iterator
- C++ 安全字符串拼接
- Venn Diagram Comparison of Boruta, FSelectorRcpp and GLMnet Algorithms
- 【C++】非原创|统计代码覆盖率(一:C)
- 数组下标从0开始
- C语言数据类型所占字节数
- C++程序设计语言练习8.6 异常处理和递归的性能代价对比
- c++学习main函数输入参数argc argv,vs2008输入参数设置,cmd常用命令
- 转:C++中获得文件大小
- pixhawk mc_pos_control.cpp源码解读
- 头文件定义全局变量等问题
- c++ STL::String::Compare (_Buf内容一致,compare不相等)
- constexpr变量
- 顶层const
- const的引用
- Char*不能赋给LPCWSTR问题解决
- auto类型说明符