C++--template
1.函数模板
函数模板不是真正的函数,而是编译器生成函数的模子。
1.1 定义
注意点:类型形参是接收类型的,不是接收数据的。如 int类型,double类型。
class 和 typename 等同。两者可相互替换。
1.2 使用
//
// Created by lp on 3/1/2023.
//
#include <iostream>
using namespace std;
//function template
template<class T>
T Max(T x,T y)
{
return x > y ? x : y;
}
int main()
{
cout<< Max<int>(3,5) <<endl;
cout<< Max<double>(3.2,3.1) <<endl;
cout<< Max<string>("abc","abd") <<endl;
return 0;
}
result:
5
3.2
abd
1.3 函数模板分析
注意点:
函数模板仅仅是一个模子
,编译器会按照函数模板这个模子生成相应的函数。
编译器编译后的源文件中就没有保存template的声明,保存的是生成的相对应的函数。
如上面使用的例子:
cout<< Max<int>(3,5) <<endl;
1.中的 Max<int>(3,5)编译器会按照模板生成 int Max(int x,int y){...}这样的函数,即函数模板的实例化。
2.调用的地方会变为 Max(3,5) 即编译过的代码应为 cout<< Max(3,5) <<endl;
编译的源码大概变成了下面的样子:
#include <iostream>
using namespace std;
int Max(int x,int y)
{
return x > y ? x : y;
}
int main()
{
cout<< Max(3,5) <<endl;
return 0;
}
1.4 函数模板扩展
1.4.1 实例化函数模板条件
1.4.2 二次编译
1.4.3 隐式推断类型实参
编译器自主做类型转换就是隐式转换。
例:
#include <iostream>
using namespace std;
//function template
template<class T>
T Max(T x,T y)
{
return x > y ? x : y;
}
int main()
{
cout<< Max<int>(3,5) <<endl; //显示推断
cout<< Max<>(3,5) <<endl; //隐式推断,由编译器自动推断
return 0;
}
1.5 函数模板重载
例:
#include <iostream>
using namespace std;
void Max(int x, int y){
cout << "1:Max(int,int)" << endl;
}
template<class T>void Max(T x, T y){
cout << "2:Max(T,T)" <<endl;
}
int main(){
int nx=10, ny=20;
Max(nx,ny); //两者匹配度相同,优先普通函数
Max<>(nx,ny); //<>就指定是模板
double dx=12.3, dy=45.6;
Max(dx,dy); //模板匹配度高故为模板函数
Max(nx,dy); //包含隐式转换就是普通函数
return 0;
}
result:
1:Max(int,int)
2:Max(T,T)
2:Max(T,T)
1:Max(int,int)
2.类模板
类模板不是真正的类,是编译器生成类的一个模子。
2.1 类模板的声明
2.2 类模板的使用
例:
#include <iostream>
using namespace std;
//类模板
template<class T>class CMath{
public:
CMath(T const& t1, T const& t2):m_t1(t1),m_t2(t2){}//类初始化,用t1给m_t1赋值,t2给m_t2赋值。
// T add(); //成员方法声明方式分开,声明部分
T add(){ //成员方法声明实现写一起方式
return m_t1 + m_t2;
}
private:
T m_t1;
T m_t2;
};
/*template<class T>T CMath<T>::add(){//成员方法实现方式分开,实现部分
return m_t1 + m_t2;
}*/
int main(){
int nx=10, ny=20;
CMath<int> m1(nx,ny); //实例化时,生成类:class CMath<int>{.....};且该生成类中只有成员变量,此时还未实例化出成员函数。只有调用成员函数时,才回实例化相应的成员函数
cout << m1.add() << endl; //成员函数被调用时才实例化出成员函数
double dx=12.3, dy=45.6;
CMath<double> m2(dx,dy); //实例化时,生成类:class CMath<double>{.....};且该生成类中只有成员变量,此时还未实例化出成员函数。
cout << m2.add() << endl; //成员函数被调用时才实例化出成员函数
string sx="hello", sy=" world";
CMath<string> m3(sx,sy); //实例化时,生成类:class CMath<string>{.....};且该生成类中只有成员变量,此时还未实例化出成员函数。
cout << m3.add() << endl; //成员函数被调用时才实例化出成员函数
return 0;
}
2.3 类模板的静态成员
2.4 类模板的递归实例化
#include <iostream>
using namespace std;
template<class T>class Array{
public:
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
int main(){
Array<Array<int> > m; //嵌套类右边两个尖括号中间应该有空格,否则编译器不认识。
for(int i=0; i<10; i++){
for(int j=0; j<10; j++){
m[i][j] = i+j;
}
}
for(int i=0; i<10; i++){
for(int j=0; j<10; j++){
cout << m[i][j] << ' ';
}
cout << endl;
}
return 0;
}
2.5 类模板扩展
2.5.1 全局特化
特化全部类型参数就是全局特化,
在全局特化的基础上,只特化某个成员方法叫成员特化,针对某种类型将整个类特化叫全局特化。
#include <iostream>
#include <cstring>
using namespace std;
//类模板
template<class T>class CMath{
public:
CMath(T const& t1, T const& t2):m_t1(t1),m_t2(t2){}
T add(){
return m_t1 + m_t2;
}
private:
T m_t1;
T m_t2;
};
//成员特化
////template后<>中一定不写具体类型代表的就是特化
template<>char* const CMath<char*const>::add(){
return strcat(m_t1, m_t2);
}
/*
//全类特化
//template后<>中一定不写具体类型代表的就是特化
template<>class CMath<char* const>{
public:
CMath<char* const>(char*const& t1, char* const& t2):m_t1(t1),m_t2(t2){}
char* const add(){
return strcat(m_t1,m_t2);
}
private:
char* const m_t1;
char* const m_t2;
};*/
int main(){
int nx=10, ny=20;
CMath<int> m1(nx,ny);
cout << m1.add() << endl;
double dx=12.3, dy=45.6;
CMath<double> m2(dx,dy);
cout << m2.add() << endl;
string sx="hello", sy=" world";
CMath<string> m3(sx,sy);
cout << m3.add() << endl;
char cx[256]="hello", cy[256]=" world";
CMath<char* const> m4(cx,cy);
cout << m4.add() << endl;
return 0;
}
2.5.2 局部特化
只特化一个类型参数就是局部特化,特化全部类型参数就是全局特化。
注意二义性问题。
例:
#include <iostream>
using namespace std;
template<class T, class D>class CMath{
public:
static void foo(){
cout << "1:CMath<T,D>::foo" << endl;
}
};
//局部特化
template<class T>class CMath<T,short>{
public:
static void foo(){
cout << "2:CMath<T,short>::foo" << endl;
}
};
template<class T>class CMath<T,T>{
public:
static void foo(){
cout << "3:CMath<T,T>::foo" << endl;
}
};
template<class T, class D>class CMath<T*,D*>{
public:
static void foo(){
cout << "4:CMath<T*,D*>::foo" << endl;
}
};
int main(){
CMath<int,double>::foo();//1
CMath<int,short>::foo();//2
// CMath<short,short>::foo();//匹配歧义 ,报错,编译器不知道2和3该选哪个
CMath<int*,double*>::foo();//1
// CMath<int*,int*>::foo();//匹配歧义,报错, 编译器不知道3和4该选哪个
return 0;
}
2.5.3 类型形参的缺省值
例:
#include <iostream>
#include <typeinfo>
using namespace std;
template<class T=short,class D=int>class CMath{
public:
void print(){
cout << "m_t:" << typeid(m_t).name() << ","
<< "m_d:" << typeid(m_d).name() << endl;
}
private:
T m_t;
D m_d;
};
int main(){
CMath<float,double> m;
m.print();
CMath<> m2;
m2.print();
return 0;
}
2.5.4 数值型的模板参数
仅限整型参数,double及字符串的都不行。
例:
#include <iostream>
using namespace std;
template<class T=double,size_t S=15>class Array{
public:
T& operator[](size_t i){
return m_arr[i];
}
size_t size(){
return S;
}
private:
T m_arr[S];
};
int main(){
Array<int> a;
for(int i=0; i<a.size(); i++)
a[i] = i+1;
for(int i=0; i<a.size(); i++)
cout << a[i] << ' ';
cout << endl;
return 0;
}
2.5.5 模板技巧
2.5.5.1 模板型成员变量
例:
#include <iostream>
using namespace std;
template<class T>class Array{
public:
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template<class D>class Sum{//求和器
public:
Sum(Array<D>& s):m_s(s){}
D add(){//求和
D d = 0;
for(int i=0; i<10; i++){
d += m_s[i];
}
return d;
}
private:
Array<D> m_s;//模板型成员变量
};
int main(){
Array<int> a;
for(int i=0; i<10; i++)
a[i] = i+1;
Sum<int> s(a);
cout << s.add() << endl;
return 0;
}
2.5.5.2 模板型成员函数
例:
#include <iostream>
using namespace std;
template<class T>class CMath{
public:
template<class D>void foo();
/* template<class D>void foo(){//成员 函数模板
cout << "CMath<T>::foo<D>()" << endl;
}*/
};
template<class T>
template<class D>void CMath<T>::foo(){
cout << "CMath<T>::foo<D>()" << endl;
}
int main(){
CMath<int> m;
m.foo<double>();
return 0;
}
2.5.5.3 模板型成员类型
例:
#include <iostream>
using namespace std;
//多层类嵌套声明
template<class X>class A{
public:
template<class Y>class B{
public:
template<class Z>class C;
};
};
//多层类嵌套实现
template<class X>
template<class Y>
template<class Z>class A<X>::B<Y>::C{
public:
template<class T>void foo(){
cout << "foo()" << endl;
}
};
int main(){
A<int>::B<double>::C<float> c;
c.foo<string>();
return 0;
}
2.5.5.4 模板型模板参数
例:
#include <iostream>
using namespace std;
template<class T>class Array{
public:
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template<class D,template<class M>class C>class Sum{//求和器
public:
Sum(C<D>& s):m_s(s){}
D add(){//求和
D d = 0;
for(int i=0; i<10; i++){
d += m_s[i];
}
return d;
}
private:
C<D> m_s;//==>Array<D> m_s;
};
int main(){
Array<int> a;
for(int i=0; i<10; i++)
a[i] = i+1;
Sum<int,Array> s(a);
cout << s.add() << endl;
return 0;
}
3.模板典型错误
3.1 嵌套依赖
例:
#include <iostream>
using namespace std;
class A{
public:
class B{
public:
void foo(){
cout << "A::B::foo()" << endl;
}
};
};
template<class T>void Func(){
typename T::B b;//嵌套依赖。
b.foo();
}
int main(){
Func<A>();
return 0;
}
3.2 依赖模板参数访问成员函数模板
例:
#include <iostream>
using namespace std;
class A{
public:
template<class T>void foo(){
cout << "A::foo<T>()" << endl;
}
};
template<class D>void Func(){
D d;
d.template foo<int>();//依赖模板参数访问成员函数模板。
}
int main(){
Func<A>();
return 0;
}
3.3 子模板访问基模板
#include <iostream>
using namespace std;
template<class T>class Base{
public:
int m_i;
void foo(){
cout << "Base<T>::foo()" << endl;
}
};
//int m_i;
//void foo(){}
template<class T,class D>class Derived : public Base<T>{
public:
// int m_i;
// void foo(){}
void bar(){
Base<T>::m_i = 100;
this->foo();
}
};
int main(){
Derived<int,double> d;
d.bar();
return 0;
}
3.4 零值初始化
例:
#include <iostream>
using namespace std;
class Integer{
public:
Integer():m_i(0){}
private:
int m_i;
friend ostream& operator<<(ostream& os, Integer const& that);
};
ostream& operator<<(ostream& os, Integer const& that){
return os << that.m_i;
}
template<class T>void Func(){
T t = T();//Integer() / int()
cout << "t=" << t << endl;
}
int main(){
Func<int>();
Func<Integer>();
return 0;
}
3.5 类模板中的成员虚函数
例:
#include <iostream>
using namespace std;
template<class T>class Base{
public:
virtual void foo(){
cout << "Base<T>::foo()" << endl;
}
};
template<class T,class D>class Derived : public Base<T>{
public:
/* void foo(){
cout << "Derived<T,D>::foo()" << endl;
}*/
/* virtual template<class M>void bar(){
}*/
};
int main(){
Derived<int,int> d;
Base<int>* pBase = &d;
pBase->foo();
pBase->bar<int>();
return 0;
}