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;
}

浙公网安备 33010602011771号