C++模板简介(AnIntroduction to C++ template)
C++模板概观
C++函数模板
C++类模板
C++操作符重载
-----------------------------
C++模板简介(1)
1.模板是C++的一种特性,允许函数或类(对象)通过泛型(generic types)的形式表现或运行
2.模板可以使得函数或类在对应不同的型别(types)的时候正常工作,而无需为每一个型别都写一份代码。
3.一个简单的例子:
->如果要写一个取两个数中较大值的函数Max,在不使用模板的情况下,我们不得不针对不同的型别提供
每一种型别的重载:
int Max(int a, int b) long Max(long a, long b)
{ {
return(a>b)?a:b; return(a>b)?a:b;
} }
C++模板简介(2)
1.一个简单的例子(续)
->如果使用模板,则可以省去一堆冗余代码,从而将函数原型缩减到非常简介的表达:
template <typename T> T Max(T a, T b)
{
return(a>b)?a:b;
}
2.C++主要有两种类型的模板
->类模板(Class template): 使用泛型参数的类(classes with generic parameters)
->函数模板(Function template): 使用泛型参数的函数(functions with generic parameters)
C++模板简介(3)
1.模板实例化
->模板的声明(declaration)其实并给出一个函数或类的完全定义(definition),只是提供了
一个函数或类的语法框架(syntactical skeleton)
->实例化是指从模板构建出一个真正的函数或类的过程,比如:
template <typename T> struct Object{…};
可以用来构建诸如Object<int>, Object<char>,Object<int*>, Object<MyClass*>等等不同型别的具体实例
2.实例化有两种类型
->显式实例化-在代码中明确指定要针对哪种型别进行实例化
->隐式实例化-在首次使用时根据具体情况使用一种何时的型别进行实例化
C++函数模板(1)
1.什么是函数模板?
->函数模板是参数化的一族函数(a family of functions)
->通过函数模板,可以定义一系列函数,这些函数都基于同一套代码,但是可以作用在不同型别的参数上
template <typename T>
inline T Max(
const T& a,
const T& b)
{
return (a>b) ? a: b;
}
定义函数模板
->定义一个函数模板,返回两数中较大的那个,该参数有两个参数:(a, b)
->参数型别未定,以模板参数T表示
->模板参数由关键字typename引入
C++函数模板(2)
1.定义函数模板(续)
->也可以使用class替代typename来定义型别参数
template <class T> inline T Max(constT& a, const T& b)
{
……
}
->从语法上讲使用class和使用typename没有区别
->但从语义上,class可能会导致误区,即只有类才能作为型别参数,而事实上T所
表达的意思不仅仅只针对类,任何型别都可以
->请尽量使用typename!
->class可以取代typename,但struct却不可以,一下写法语法上是错误的:
// this is wrong!!!
template <struct T> inline TMax(const T& a, const T& b) { … }
C++函数模板(3)
1.模板函数的使用
调用Max,用int,float,以及std::wstring作为模板参数替换T
对于不同的型别,都从模板实例化出不同的函数实体
但是不可以使用不同型别的参数来调用Max,因为编译器在编译时已经知道Max函数需要传递的型别
int i= 7, j = 30;
_tprintf(TEXT("Max(i, j) = %d\n"),Max(i,j));
double f= -1.8, g = -0.9;
_tprintf(TEXT("Max(f, g) = %f\n"),Max(f,g));
std::wstring s1=TEXT("mathmmatics"), s2 = TEXT("math");
_tprintf(TEXT("Max(s1, s2) =%s\n"), Max(s1,s2));
Max(i,f); // compile error: templateparameter 'T' is ambiguous
C++函数模板(4)
1.模板实例化
->用具体型别替代模板参数T的过程叫做实例化;从而产生了一个模板实例
->一旦使用函数模板,这种实例化过程便由编译器自动触发,不需要额外去请求模板实例化
->如果实例化一种型别,而该型别内部并不支持函数所使用的操作,那么就会导致一个编译
错误。
C++函数模板(5)
1.结论:模板被编译了两次
1)没有实例化之前,检查模板代码本身是否有语法错误
2)实例化期间,检查对模板代码的调用是否合法
C++函数模板(6)
1.参数推导
->模板参数是由传递给模板函数的实参决定的
->不允许自动型别转换:每个T必须严格匹配!
Max(1,2) // OK: 两个实参的型别都是int
Max(1,2.0) // ERROR: 第一个参数型别是int, 第二个参数型别是double
->一般有两种处理这种错误的方法:
1)用static_cast或强制转换参数型别以使两者匹配
Max(static_cast<double>(1),2.0)
2)显式指定T的型别
Max<double>(1, 2.0)
C++函数模板(7)
1.函数模板重载
->函数模板也可以像普通函数一样被重载
->非模板函数可以和同名的模板函数共存
->编译器通过函数模板参数推导来决定使用调用哪个重载
// 普通函数
inline int const&Max(const int const& a, const int const& b) ---①
template <typename T>
inline T const&Max(const T const& a, const T const& b) ---②
template <typename T>
inline T const&Max(const T const& a, const T const& b, const T const& c) ---③
C++函数模板(8)
1.函数模板重载(续)
->Max(7, 42, 68): 调用接受三个参数的模板 - ③
->Max(7.0, 42.0):调用Max<double>(参数推导) - ②
->Max('a', 'b'):调用Max<char>(参数推导) - ②
->Max(7, 42):调用非模板函数,参数型别为int - ① 其他因素都相同
的情况下,重载裁决过程调用非模板函数,而不是从模板产生实例
->Max<>(7, 42):调用Max<int>(参数推导) - ② 允许空模板参数列表
->Max<double>(7, 42): 调用Max<double>(无需参数推导) - ②
->Max('a', 42.7): 调用非模板函数,参数型别为int - ①对于型别不同
的参数只能调用非模板函数(char型别'a'和double型别都将转化为int型别)
C++函数模板(9)
1.总结
->对于不同的实参型别,模板函数定义了一族函数
->当传递模板实参的时候,函数模板依据实参的型别进行实例化
->可以显式指定模板的实参型别
->函数模板可以重载
->当重载函数模板时,将改变限制在:显式指定模板参数
->所有的重载版本的声明必须位于它们被调用的位置之前