C++--template

1.函数模板

函数模板不是真正的函数,而是编译器生成函数的模子。

1.1 定义

image
注意点:类型形参是接收类型的,不是接收数据的。如 int类型,double类型。
class 和 typename 等同。两者可相互替换。

1.2 使用

image

//
// 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 函数模板分析

image
注意点:
函数模板仅仅是一个模子,编译器会按照函数模板这个模子生成相应的函数。
编译器编译后的源文件中就没有保存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 实例化函数模板条件

image

1.4.2 二次编译

image

1.4.3 隐式推断类型实参

编译器自主做类型转换就是隐式转换。
image
例:


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

image

1.5 函数模板重载

image
例:

#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 类模板的声明

image

2.2 类模板的使用

image
例:

#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 类模板的静态成员

image

2.4 类模板的递归实例化

image

#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 全局特化

特化全部类型参数就是全局特化,
在全局特化的基础上,只特化某个成员方法叫成员特化,针对某种类型将整个类特化叫全局特化。
image

#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 局部特化

只特化一个类型参数就是局部特化,特化全部类型参数就是全局特化。
注意二义性问题。
image
例:

#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 类型形参的缺省值

image
例:

#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及字符串的都不行。
image

例:

#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 模板型成员变量

image
例:

#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 模板型成员函数

image
例:

#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 模板型成员类型

image
例:

#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 模板型模板参数

image
例:

#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 嵌套依赖

image
例:

#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 依赖模板参数访问成员函数模板

image
例:

#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 子模板访问基模板

image

#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 零值初始化

image
例:

#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 类模板中的成员虚函数

image
例:

#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;
}
posted @ 2023-03-01 16:52  Panor  阅读(41)  评论(0编辑  收藏  举报