C++之模板特性详解!(3千字长文)

C++之模板特性详解!

非类型模板参数

#define N 10
template<class T>
//静态的数组
class Array
{
private:
	T _a[N];
};
int main()
{
	Array<int> a1;    //这样子数组已经写死了!
	Array<double> a2;  //如果我们不想要10想要其他的大小那么我们就必须修改宏!这样子其实是不方便的!
	return 0;
}

==如果我们想要一个能够灵活定义的固定数组

这时候宏就不够方便灵活了!为了能够适应这种状况!于是就有了非类型模板参数!

template<class T,size_t N = 10>//模板可以有缺省值
class Array
{
private:
	T _a[N];
};
int main()
{
	Array<int,10> a1;   
	Array<double,10000> a2;
 //这样就可以规定我们想要的固定的数组大小了!
	return 0;
}

非类型模板参数是一个整形常量!

实际中C++的STL库的array里面也是使用非类型模板参数来实现了的!

image-20230329172725514

函数模板也是可以使用这个非类型模板参数

template<class T,size_t N>
void Func(const T& x)
{
	cout << N << endl;
}
template<class T,double N>
void Func2(const T& x)
{
	cout << N << endl;
}
int main()
{
	Func<int, 100>(1);
    FUnc2<int,1.00>(1);
	return 0;
} 

image-20230329210150404

非类型模板参数是不可以是非整形的!

浮点数、类对象以及字符串是不允许作为非类型模板参数的。

template<class T,size_t N>
void Func(const T& x)
{
	cout << N << endl;
}
int main()
{
	int a = 10;
	Func<int, a>(1);
	return 0;
}

image-20230329210626012

非类型模板参数必须给的是一个常量!变量是不行的!

模板的特化

函数模板特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结 果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

例如下面的例子

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}

	friend ostream& operator<<(ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}

private:
	int _year;
	int _month;
	int _day;
};
template<class T>
bool Less(T x, T y)
{
	return x < y;
}
int main()
{
	cout << Less(1, 2) << endl; //结果正确

	Date d1(2019, 1, 1);
	Date d2(2019, 1, 2);
	cout << Less(d1, d2) << endl; //结果正确

	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << Less(p1, p2) << endl; //可以比较但是结果错误
	return 0;
}

image-20230329211834438

为什么会发生这种情况呢?因为我们希望的比较的不是日期类的指针的地址的大小!而是希望比较日期类的内容!

所以如果能够对针对某些类型进行特殊处理那就是最好的!

这种特殊处理我们就叫做特化!

template<class T>
bool Less(T x, T y)
{
	return x < y;
}
//对于Date*类型进行偏特化!
template<>
bool Less<Date*>(Date* x, Date* y)
{
	return *x < *y;
}

image-20230329212534258

这样子就可以符合我们想要的行为了!

下面的会去调用特化的哪一个!

偏特化是对模板的特化,是一种特殊情况!

当然了也有人回想那为什么不直接写一个对应的函数?非得要什么偏特化?

bool Less(Date* x, Date* y)
{
	return *x < *y;
}

虽然这样子也是可以的但是,如果遇到了类模板就不行了!函数模板能用这个解决是因为有函数重载!

类模板的特化

全特化
template<class T1, class T2>
class Base
{
public:
	Base()
	{
		cout << "Base<T1,T2>" << endl;
	}
public:
	T1 _d1;
	T2 _d2;
};
//假设如果我们想要对某种特定类进行特殊处理的话我们应该办?
//函数模板可以写一个普通的函数出来!但是类就不可以了!
//这就是对上面类的特化
template<>
class Base<double, double>
{
public:
	Base()
	{
		cout << "Base<double,double>" << endl;
	}
private:
};
//里面的内容可以自由定义,只是说如果是double的参数,那么就是用这个特化的模板类!不一样是要一样的!
int main()
{
	Base<int, int> b1;
	Base<double, double> d1;
	return 0;
}

image-20230329214119420

另一个例子就是优先级队列的插入时候的比较

image-20230330144027958

我们看到如果我们使用的是data类的时候,我们就要显示的去写一个仿函数!

但是有了类模板特化!我们就有了另一种新的解决办法!

我们可以直接将less和greater等仿函数进行一次特化!我们不是对那种很大的类进行特化!我们一般是对仿函数之类的进行特化!

上面的是全特化!就是对所有的参数进行特化!

半特化/偏特化

全特化的意思就是对全部的模板参数进行特化!

半特化就是只对部分的参数进行特化!

template<class T1, class T2>
class Base
{
public:
	Base()
	{
		cout << "Base<T1,T2>" << endl;
	}
public:
	T1 _d1;
	T2 _d2;
};
template<>//全特化
class Base<double, char>
{
public:
	Base()
	{
		cout << "Base<double,char>" << endl;
	}
private:
};
template<class T>//偏特化
class Base<T, char>
{
public:
	Base()
	{
		cout << "Base<T,char>" << endl;
	}
private:
};

int main()
{
	Base<int, int> b1;
	Base<int ,char> b2;//优先匹配偏特化
	Base<long long ,char> b3;//优先匹配偏特化
	Base<double,char> b4;//和全特化完全匹配!那么就匹配全特化!
	return 0;
}

image-20230330151030455

如果偏特化更加的合适!那么就会优先去匹配半特化/偏特化!而不是原模板

只要你满足偏特化的那个特化的参数那么就会去匹配偏特化!

如果和全特化完全匹配那么就会优先去匹配全特化而不是偏特化!

可以简单的记忆 就像是我们吃东西!有成品就吃成品,没有成品就吃半成品!

吃半成品就看那个半成品的参数匹配的更多!(比如有三个模板参数,有一个模板参数的偏特化,和两个模板参数的偏特化。如果能匹配上两个!那么就用两个的!而不是一个!)

只有什么都不匹配的时候,才去匹配原模板!

偏特化另一个用途——限制参数类型
template<class T1, class T2>
class Base<T1*, T2*>//这是一种更加宽泛的偏特化!是对指针这个类型进行特化!
{
public:
	Base()
	{
		cout << "Data<T1*,T2*>" << endl;
	}

};
int main()
{
	Base<int, int> b1;
	Base<int*, int*> b3;
	Base<char*, char*> b4;//只要是指针都会走这个!
	return 0;
}

image-20230330151904851

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

};
int main()
{
	Base<int, int> b1;
	Base<int&,int&> b2;
	Base<double&, double&> b3;
	return 0;
}

image-20230330152224400

引用也是可以进行偏特化!

特化的本质体现了编译器的参数匹配原则——只要有这个参数的偏特化那么就优先使用这个参数的偏特化!

有现成的吃现成的,没有现成的吃半成品,没有半成品最后才去自己搞

模板的优缺点

【优点】

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

【缺陷】

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误
  3. 对于分离编译支持不好!

转存中…(img-CDTgVUsT-1680705500911)]

引用也是可以进行偏特化!

特化的本质体现了编译器的参数匹配原则——只要有这个参数的偏特化那么就优先使用这个参数的偏特化!

有现成的吃现成的,没有现成的吃半成品,没有半成品最后才去自己搞

模板的优缺点

【优点】

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

【缺陷】

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误
  3. 对于分离编译支持不好!
  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
此用户手册描述的是三星公司的 16/32 位精简指令集(RISC)微处理器 S3C2440A。三星公司的 S3C2440A 为手持设备和普通应用提供了低功耗和高性能的小型芯片微控制器的解决方案。为了降低整体系统成本,S3C2440A 还提供了以下丰富的内部设备。 S3C2440A 基于ARM920T 核心,0.13µm 的CMOS 标准宏单元和存储器单元。低功耗,简单,精致,且全静 态设计特别适合于对成本和功率敏感型的应用。它采用了新的总线架构如先进微控制总线构架(AMBA) 。 S3C2440A 的突出特点是其处理器核心,是一个由Advanced RISC Machines(ARM)公司设计的 16/32 位 ARM920T的RISC 处理器。ARM920T 实现了 MMU,AMBA 总线和哈佛结构高速缓冲体系结构。这一结构具有独 立的 16KB指令高速缓存和 16KB 数据高速缓存。每个都是由具有 8字长的行(line)组成。 通过提供一套完整的通用系统外设,S3C2440A减少整体系统成本和无需配置额外的组件。综合对芯片的功能 描述。 本手册将介绍 S3C2440A 集成的以下片上功能: ● 1.2V内核供电, 1.8V/2.5V/3.3V储存器供电, 3.3V外部I/O供电,具备16KB的指令缓存和16KB的数据缓存和MMU 的微处理器 ● 外部存储控制器(SDRAM 控制和片选逻辑) ● LCD 控制器(最大支持 4K 色 STN 和 256K 色 TFT)提供 1 通道 LCD 专用 DMA ● 4 通道 DMA 并有外部请求引脚 ● 3 通道 UART(IrDA1.0, 64 字节发送 FIFO 和 64 字节接收 FIFO) ● 2 通道 SPI ● 1 通道 IIC 总线接口(支持多主机) ● 1 通道 IIS 总线音频编码器接口 ● AC’97 编解码器接口 ● 兼容 SD 主接口协议 1.0 版和 MMC 卡协议 2.11 兼容版 ● 2 通道 USB 主机/1 通道 USB 设备(1.1 版) ● 4 通道 PWM 定时器和 1 通道内部定时器/看门狗定时器 ● 8 通道 10 位 ADC 和触摸屏接口 ● 具有日历功能的 RTC ● 摄像头接口(最大支持 4096×4096 像素输入;2048×2048 像素输入支持缩放) ● 130 个通用 I/O 口和 24 通道外部中断源 ● 具有普通,慢速,空闲和掉电模式 ● 具有 PLL 片上时钟发生器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为世界献上祝福

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值