模板:编程界的活字印刷术

一、函数模板

1、函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数(自定义类型也可以)

#include<iostream>
#include<string>
using namespace std;

 //泛型编程
 //函数模板
//template<class Tp>
template<typename T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

template<typename T1, typename T2>
T1 Func(const T1& x, const T2& y)
{
	cout << x << " " << y << endl;

	return x;
}

// 函数模板实例化生成具体函数
// 函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数(自定义类型也可以)
int main()
{
	int a = 0, b = 1;
	Swap(a, b);

	double c = 1.1, d = 2.2;
	Swap(c, d);

	Func(1, 2);
	Func(1, 2.2);

	return 0;
}

2、通过实参传递的类型推演T的类型,可能会推导歧义
解决方法:显示实例化:Add<int>()
(有些函数无法自动推,只能显示实体化)

#include<iostream>
#include<string>
using namespace std;

template<class T>
T Add(const T& left, const T& right)
{
    return left + right;
}

template<class T>
T* Alloc(int n)
{
    return new T[n];
}

int main()
{
    int a1 = 10, a2 = 20;
    double d1 = 10.1, d2 = 20.2;
    // 实参传递的类型,推演T的类型
    cout << Add(a1, a2) << endl;
    cout << Add(d1, d2) << endl;
    cout << Add(a1, (int)d1) << endl;
    cout << Add((double)a1, d1) << endl;

    // 显示实例化,用指定类型实例化
    cout << Add<int>(a1, d1) << endl;
    cout << Add<double>(a1, d1) << endl;

    // 有些函数无法自动推,只能显示实例化
    double* p1 = Alloc<double>(10);

    return 0;
}

3、注意:

普通类,类名和类型是一样
类模板,类名和类型不一样
类名:Stack
类型:Stack<T>

#include<iostream>
#include<string>
using namespace std;

// 类模板
template<class T>
class Stack//类名
{
public:
//类里定义
	Stack(size_t capacity = 3);

	void Push(const T& data);

	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}

private:
	T* _array;
	int _capacity;
	int _size;
};

//类型:Stack<T>
//类外声明
template<class T>
Stack<T>::Stack(size_t capacity)
{
	_array = new T[capacity];

	_capacity = capacity;
	_size = 0;
}

template<class T>
void Stack<T>::Push(const T& data)
{
	_array[_size] = data;
	_size++;
}

显然,template的作用范围是模板下面第一个类/函数。类模板的成员函数是函数模板.
而用类模板实现栈时,需类里定义,类外声明(模板参数也要声明)
(不分离也可以,就是难看概况)

二、类模板、容器与仿函数

1、模板的三种用法:控制类型、控制适配器模式、控制仿函数
2、非类型模板参数:必须是整形常量

// 静态栈
// 非类型模板参数必须是整形常量
template<class T, size_t N>
class Stack
{
	T _a[N];
	int _top;
};


三、模板的特化(效果跟实例化出函数重载一样)

函数模板特化:

//仿函数
template<class T>
bool Less(T left, T right)
{
	return left < right;
}

//函数模板的特化
template<>
bool Less<int*>(int* left, int* right)
{
	return *left < *right;
}

bool Less(int* left, int* right)
{
	return *left < *right;
}

template<class T>
bool Less(T* left, T* right)
{
	return *left < *right;
}

类模板的全特化和偏特化:

//类
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

// 针对int double要进行特殊处理
// 全特化
template<>
class Data<int, double>
{
public:
	Data() { cout << "Data<int,double>" << endl; }
private:
};

// 偏特化 : 特化部分参数
template<class T1>
class Data<T1, double>
{
public:
	Data() { cout << "Data<T1, double>" << endl; }
private:
};

// 偏特化 : 可能是对某些类型的进一步限制
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }
private:
};

template<class T1, class T2>
class Data<T1&, T2&>
{
public:
	Data() { cout << "Data<T1&, T2&>" << endl; }
private:
};

四、模板的分离编译

复习:编译链接过程
Stack.h  Stack.cpp Test.cpp
预处理:头文件展开/宏替换/条件编译/去掉注释
Stack.i  Test.i
编译:检查语法,生成汇编代码
Stack.s  Test.s
汇编:汇编代码转换成机器码(二进制)
Stack.o  Test.o  符号表(存函数地址)
链接:可执行程序:xxx.exe/a.out
编译:声明(承诺)
编译:定义(直接兑现)
链接:找到定义(兑现承诺)

链接错误解决方式:显示实例化

temlate
class stack<int>;

五、总结

优点:
1、模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性。(适配器/仿函数)
缺陷:
1、模板会导致代码膨胀问题,也会导致编译时间变长
2、出现模板编译错误时,错误信息非常凌乱,不易定位错误
 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值