1.函数模板
1.1概念
1)函数模板用来生成特定类型的函数版本的公式
2)函数模板的形式:
template <typename T> int compare(const T &v1, const T &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; } cout << compare(1, 0) << endl; //T为int,编译器为我们实例化一个特定版本的函数
3)实例化:调用函数模板时,编译器通过输入的实参来推断模板实参,然后用这个模板实参实例化一个特定版本的函数
4)函数模板和函数一样可以被inline和constexpr修饰
1.2类型参数
1)类型参数用关键字typenname或class修饰(两者一样),在函数模板中,可以将类型参数看作类型说明符,就像内置类型或类类型一样使用
1.3非类型参数
1)在模板中还可以定义非类型参数,一个非类型参数表示一个值而非一个类型,通过一个特定的类型名而非关键字typenname或class来指定
template<unsigned n, unsigned m> int compare(const char(&p1)[n], const char(&p2)[m])//p1是引用,对const char[n]的引用 { return strcmp(p1, p2); } int main() { cout << compare("hhhhhi", "mom");//打印:-1,编译器会实例化出以下版本:int compare(const char (&p1)[7], const char (&p2)[4]) return 0; }
1.4模板编译
1)当编译器遇到一个模板定义时,并不生成代码,只有实例化模板时才会生成代码
2)调用函数时,编译器只需要函数的声明,使用类对象时,需要类的定义,所以一般函数声明和类定义放在头文件中,函数的定义(包括类的成员函数)放在源文件中;模板则不同:编译器需要掌握函数模板或类模板成员函数的定义,所以模板的头文件一般即包含声明也包括定义
1.5模板编程的两个重要原则
1)模板的形参是引用:保证了模板可以用于不能拷贝的类型,同时,对于大对象来说,不拷贝还能使函数运行得更快
2)函数体中的条件判断仅使用 < 比较运算:只是用<比较运算,就降低了对类型的要求,大多类型都支持<运算
总之,模版编程就是应该尽量减少对实参类型的要求
2.类模板
2.1概念
1)类模板是用来生成了类的公式
2)与函数模板不同的是,编译器不能为类模板推断模板参数类型,因为我们总是要提供一些额外信息来指定模板到底实例化成什么样的类,我们必须在模板名后的尖括号内添上信息;这些额外信息叫显式模板实参
template <typename T> class Blob { …… }; Blob<int> bb; //尖括号上写上int,编译器才能实例化一个特定的类
2.2成员函数
1)与类一样,类模板的成员函数可以在内部或外部定义,在内部定义,隐式声明为内联