1、引子ios
考虑求两数较大值函数max(a,b)
对于a,b的不一样类型,都有相同的处理形式:
c++
return a < b ? b : a;编程
用已有方法解决:
(1)宏替换 #define max(a,b) ((a)< (b) ? (b) : (a))
函数
存在的问题:避开类型检查工具
(2)重载
spa
存在的问题:须要许多重载版本设计
(3)使用函数模板
指针
2、模板对象
模板是一种参数化的多态工具
所谓参数化的多态性,是指将程序所处理 的对象的类型参数化,使一段程序代码能够用于处理多不一样类型的对象。
采用模板编程,能够为各类逻辑功能相同而数据类型不一样的程序提供一种代码共享的机制。
ci
模板包括函数模板(function template)、类模板(class template)。本文主要讨论函数模板
3、函数模板
(一)、函数模板的使用
函数模板的通常说明形式以下:
template < 模板形参表>
返回值类型 函数名(模板函数形参表){
//函数定义体
}
一、函数模板的定义以关键字template开头
二、template以后<>中是函数模板的参数列表
三、函数模板的参数是类型参数,其类型为class或typename
template<class T>
template<class T1, class T2>
四、模板形参在模板中做为一种类型使用,能够用于函数的形参、函数返回值和函数的局部变量
五、每一个模板形参要在函数的形参列表中至少出现一次
六、模板参数名的做用域局限于函数模板的范围内
(二)、函数模板的使用
一、函数模板为全部的函数提供惟一的一段函数代码,加强了函数设计的通用性
二、使用函数模板的方法是先说明函数模板,而后实例化成相应的模板函数进行调用执行
函数模板不是函数,不能被执行
置换代码中的类型参数获得模板函数——实例化
实例化后的模板函数是真正的函数,能够被执行
三、模板被编译了两次
实例化以前,先检查模板代码自己,查看语法是否正确;在这里会发现语法错误,若是遗漏分号等。
实例化期间,检查模板代码,查看是否全部的调用都有效。在这里会发现无效的调用,如该实例化类型不支持某些函数调用或操做符等。
四、普通函数只须要声明,便可顺利编译,而模板的编译须要查看模板的定义(声明和定义需放在同个.h文件)
(三)、函数模板特化
假设如今咱们有这样一个模板函数max:
template <typename T>
const T& max(const T& a, const T& b)
{
return a < b ? b : a;
}
而后如今咱们要比较两个字符串的大小,如:
const char* str1 = "aaa";
const char* str2 = "zzz";
此时若是按通常的实例化,比较的将是str1 和 str2 的大小,即比较指针数值大小,而不是字符串大小,故咱们须要实现一个模板函数的特化,以下:
template<>
const char* const& max(const char* const& a, const char* const& b)
{
return strcmp(a, b) < 0 ? b : a;
}
(四)、重载函数模板,非模板函数重载
C++语言能够重载一个函数模板
用户能够用非模板函数重载一个同名的函数模板
max.h:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#ifndef _MAX_H_ #define _MAX_H_ #include <iostream> using namespace std; template <typename T> const T &max(const T &a, const T &b) { cout << "template max(const T& a, const T& b)" << endl; return a < b ? b : a; } // 函数模板重载 template <typename T> const T &max(const T &a, const T &b, const T &c) { cout << "template max(const T& a, const T& b, const T& c)" << endl; return ::max(a, b) < c ? c : ::max(a, b); // ::max 会调用非模板函数 } // 非模板函数重载 const int &max(const int &a, const int &b) { cout << "max(const int& a, const int& b)" << endl; return a < b ? b : a; } // 函数模板特化 template <> const char *const &max(const char *const &a, const char *const &b) { cout << "template <> max(const char* const&a, const char* const& b)" << endl; return strcmp(a, b) < 0 ? b : a; } // 非模板函数重载 const char *const &max(const char *const &a, const char *const &b) { cout << "max(const char* const&a, const char* const& b)" << endl; return strcmp(a, b) < 0 ? b : a; } #endif // _MAX_H_ |
main.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <iostream> #include <string> using namespace std; #include "max.h" class Test { public: friend bool operator<(const Test &t1, const Test &t2) { cout << "operator<(const Test& t1, const Test& t2)" << endl; return true; } }; int main(void) { //与 std::max 区别开来 cout <<::max(5.5, 6.6) << endl; // 自动推导 max(const double&, const double&); cout <<::max('a', 'c') << endl; // 自动推导 max(const char&, const char&); Test t1; Test t2; ::max(t1, t2); // Test::operator<(const Test& t1, const Test& t2) const char *str1 = "aaa"; const char *str2 = "zzz"; cout <<::max(str1, str2) << endl; //优先选择非模板函数 cout <<::max<>(str1, str2) << endl; //指定使用模板,进而找到模板特化 // cout<<::max<const char*>(str1, str2); // 显式指定模板特化函数max(const char* const&a, const char* const& b) cout <<::max(1, 5, 3) << endl; // 模板匹配,进而自动推导 cout <<::max('a', 50) << endl; // 'a'即97;选择非模板函数(char能够隐式转换成int) cout <<::max(97, 100) << endl; // 优先选择非模板函数 cout <<::max<>(97, 100) << endl; // 指定使用模板,进而自动推导 // cout<<::max<>('a', 50)<<endl; // Error,指定使用模板,但编译器不知道怎样推导 cout <<::max<int>(97, 100) << endl; // 显式指定模板函数max(const int&, const int&) cout <<::max<int>('a', 50) << endl; // 显式指定模板函数max(const int&, const int&) return 0; } |
函数模板能够经过传递的参数类型自动推导,查看是否有合适的函数实例可用,而类模板则必须显式说明模板的类型参数,这样才能实例化模板类实例。
4、模板的偏特化
模板的偏特化是指须要根据模板的某些但不是所有的参数进行特化
(1) 类模板的偏特化
例如c++标准库中的类vector的定义
template <class T, class Allocator>
class vector { // … // };
template <class Allocator>
class vector<bool, Allocator> { //…//};
这个偏特化的例子中,一个参数被绑定到bool类型,而另外一个参数仍未绑定须要由用户指定。
(2) 函数模板的偏特化
严格的来讲,函数模板并不支持偏特化,但因为能够对函数进行重载,因此能够达到相似于类模板偏特化的效果。
template <class T> void f(T); (a)
根据重载规则,对(a)进行重载
template < class T> void f(T*); (b)
若是将(a)称为基模板,那么(b)称为对基模板(a)的重载,而非对(a)的偏特化。C++的标准委员会仍在对下一个版本中是否容许函数模板的偏特化进行讨论。
参考:
C++ primer 第四版 Effective C++ 3rd C++编程规范