17. 模板
调用模板函数时,编译器根据调用参数推断出模板参数,用来实例化一个特定版本的函数。
template<typename T> T Add(T a, T b) { return a + b; } template<typename T,typename U> T Add(T a, U b) { return a + b; } //模板特例化,template后跟一对空的<>,并为所有模板参数提供实参 template<> char *Add(char *a, const char *b) { return strcat(a, b); } int Add(int, int) { cout << "!!!" ; return 0; } int main() { Add(1, 2);//普通函数优先于模板 Add(1.2, 2.3);//编译器自动推断模板参数类型 Add(1LL, 2);//编译器自动推断模板参数类型 Add(1, 'a');//编译器自动推断模板参数类型 Add<double, long long>(1, 'a');//指定类型 char buff[100] = "Hello"; Add(buff, "World");//特例化的优于普通的模板 return 0; }
模板再使用时才会实例化,产生对应类型的二进制代码。如果没有实例化,则编译生成的obj文件中不存在模板相关的代码,所以模板的声明和实现都放在头文件中。否则会发生链接错误,因为只有声明,没有实现。
成员函数模板
class Foo { public: template<typename T> void Print(T val) { cout << n << " " << val; } private: int n = 1; }; int main() { Foo foo; foo.Print(1);//自动推断参数类型 foo.Print(1.2);//自动推断参数类型 foo.Print<double>(1.2);//显示指定参数类型 return 0; }
类模板:
template<typename T> class Foo { public: Foo(T val); void Print(T val) { cout << n << " " << val << endl; } private: T n; }; template<typename T> Foo<T>::Foo(T val) :n(val) {} template<> class Foo<char> {//类模板特例 public: Foo(char val); void Print(char val) { cout << "类模板特例:"; cout << n << " " << val << endl; } private: char n; }; Foo<char>::Foo(char val):n(val) {} template<typename T> class Child :public Foo<T> {//继承,Child也是模板 public: Child(T val) :Foo<T>(val) { } }; class Child2 :public Foo<double> {//Child2不是模板,是具体的类 public: Child2(double val) :Foo<double>(val) { } }; int main() { Foo<int> foo(11);//类模板必须提供显示模板实参,编译器无法推导 foo.Print(12); Foo<double> foo1(1.222);//类模板必须提供显示模板实参,编译器无法推导 foo1.Print(3.14); Foo<char> foo2('A');//类特例 foo2.Print('B'); Child<int> child(1); Child2 child2(111); return 0; }