泛型编程:不考虑具体数据类型的编程
函数模板:可用不同参数类型进行调用的函数(类型可以被参数化)
语法:
template < typename T > // T 泛指任意的数据类型 void Swap(T& a, T& b) { T c = a; a = b; b = c; }
语法规则:template 关键字用于声明开始进行泛型编程(声明一个模板)。typaname 用于声明泛指类型。
调用规则:自动类型推导调用(根据函数调用时实参的类型设置T的类型)--> Swap(a,b)。具体类型显示调用(函数调用时指定T的类型)--> Swap<float>(a,b)。
函数模板原理:函数模板是个模子,编译器通过模板和具体参数类型产生不同的函数。编译器会进行两次编译,第一次检测模板代码,第二次检测加参数后的具体函数代码。
注意:模板本身不是函数,模板本身不允许隐式类型的转换。自动推导时:必须参数匹配。显示指定时:能进行隐式类型转换。
#include <iostream> #include <string> using namespace std; class Test { Test(const Test&); // 拷贝构造函数为是由函数,Test类无法进行拷贝构造 public: Test() {} }; template < typename T > // 第一次编译:编译时进行模板的检查 void Swap(T& a, T& b) { T c = a; a = b; b = c; } typedef void(FuncI)(int&, int&); typedef void(FuncD)(double&, double&); typedef void(FuncT)(Test&, Test&); int main() { FuncI* pi = Swap; // 编译器自动推导 T 为 int 1.自动类型推导 2.产生一个函数 3.将函数地址赋给pi FuncD* pd = Swap; // 编译器自动推导 T 为 double FuncT* pt = Swap; // error 第二次编译时:编译器自动推导 T 为 Test,并生成一个参数为Test函数,但是函数内部有拷贝,出错 cout << "pi = " << reinterpret_cast<void*>(pi) << endl; cout << "pd = " << reinterpret_cast<void*>(pd) << endl; cout << "pt = " << reinterpret_cast<void*>(pt) << endl; return 0; }
多参函数模板:
语法:
template <typename T1,typename T2,typename T3> T1 Add(T2 a,T3 b) { return static_cast<T1>(a+b); }
int ret = Add<int, float, double>(0.5, 0.8); // 函数在此才被创建
注意:多参函数模板无法推导返回值类型,所以返回值类型必须显示指定。
可以从左向右指定参数类型。
推荐将返回值参数作为第一个类型参数来声明。
// T1 = int, T2 = double, T3 = double int r1 = Add<int>(0.5, 0.8); // T1显式指定返回值类型 (部分显示指定类型参数),T2,T3由编译器自动推导 // 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);
函数模板与被重载时:
1. C++编译器优先考虑重载普通函数。
2. 空实参列表模板限定编译器重载时只匹配模板Max<>(a,b)。
#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) //函数重载函数模板 { 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 = 1; int b = 2; // 进行重载时的选择根据参数类型,个数 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', 100) << endl; // 普通函数 Max(int, int) return 0; }
函数模板特化:特化就是模板的特殊形式,根据参数分为完全特化(参数类型完全确定),部分特化(参数类型相同)。
函数模板特化只支持函数模板的完全特化。
template <typename T> void function(T a,T b) {
/* do something */
} template < > void function<type>(type a,type b) //函数模板完全特化 {
/* do something */
}
函数特化遇上函数重载:
#include <iostream> #include <string> using namespace std; template < typename T > bool function(T a, T b) // 函数模板 {
/* do something */
} template < > bool function<double>(double a, double b) // 函数模板的完全特化 {
/* do something */
} bool function(double a, double b) // 全局函数对函数模板进行重载 {
/* do something */
} int main() { function( 1, 1 ); // 根据参数类型,调用函数模板 function( 0.001, 0.001 ); // 根据参数类型,优先调用重载的全局函数 function<>( 0.001, 0.001 ); // 使用 function<>() 时只考虑调用函数模板,根据参数选择完全特化 return 0; }