C++模板进阶

目录

一、模板参数:

二、非类型模板(传常量)

1、定义:

2、理解

3、应用场景

二、模板的缺省参数

三、按需实例化

1、理解

2、具体实例

a、上述代码明显是错误的

b、只调用func1运行没有问题

c、调用func2就会出问题

四、模板特化

1、函数模板特化

a、定义

b、理解

2、类模板特化

a、定义格式

1)类模板

2)半特化/偏特化

3)全特化

4)按需调用

​编辑b、理解

五、模板声明定义分离

1、不支持声明定义分离

a、为什么?

b、解决办法?

六、模板的优缺点

1、优点

2、缺点



一、模板参数:

template<class T>

模板怎么理解?
模板就是参数
模板是一个半成品,少一个东西实例化
模板就像是一个模具,丢进去什么东西,就变成什么东西
你丢进去铁,就变成铁剑
你丢进去金,就变成金剑
你丢进去银,就变成银剑
你丢进去铜,就变成铜剑
剑的作用都是一样的,但是可能不同的剑用于不同的场景

函数参数:(T 对象)
模板参数:<class 类型>

模板分:函数模板(可以推导),类模板(必须实例化)


二、非类型模板(传常量)

目前只支持整型int char unsigned_int size_t 

1、定义:

template <size_t N>

2、理解


一般传常量使用宏
但是利用宏有一个致命缺点:就是不可改变
例如,我要一个10个大小的数组,如果宏是10还好说
如果我要的是20呢?1000000000呢?
宏无法解决,要解决,只有再写一个类
而有了非类型模板参数,就可以了。
数组参数为N
你传N的参数为10,就开辟10个空间
你传N的参数为100000,就开辟100000个空间
那么,它是这么解决呢?
事实上,本质上还是生成了多个类
你传10,编译器生成10的类
你传1000,编译器生成1000的类
...
以此类推
所以,事实上是原本要你自己写的类
变成了编译器帮你写


3、应用场景


我们想要控制一个静态数组的大小
注意,不是动态开,而是静态。动态开辟有new
静态开辟是在编译阶段就直接开好了
动态开辟是在运行阶段开辟

二、模板的缺省参数


直接给缺省

template <size_t N = 10>

三、按需实例化

1、理解

在编译过程中,编译器会根据需求实例化,生成具体的类,再进行语法编译

什么意思?
我有一个模板类,类内部有100个成员函数,但是我只用到了其中一个
例如有100个成员函数,但是我只用了一个,剩下的99个和程序运行毫无关系,我有必要加载吗?
没有必要
所以,我生成的类,并不是按照模板严格的从头到尾全部加载
而是,我需要什么,我就加载什么


实例化时,会按需实例化
什么意思?
调用那个成员函数,就实例化那个成员函数
例如说,要调用成员函数a,就只实例化了a
但是对于不被调用的成员函数b,就不会实例化
什么叫做实例化?说白了就是用没用,实例化了,就是用到了;没有实例化,就是没有用到
假如你的成员函数b内部有语法错误
但是因为没有实例化,也就是没有用到
既然都没有用到,我编译器有必要对你进行检查吗?
完全没有必要
所以,不检查,那你有错误,我能知道吗?
不知道
所以,即使你有语法问题,不会报错,但是我没有检查,会报错吗?
不会报错。

2、具体实例

namespace me
{
	template<class T>
	class A
	{
	public:
		void func1( )
		{
			cout << "no problem" << endl;
		}

		void func2()
		{
			cout << "problem" << endl;
			func1(1,2,3,4,5,6,7,8,9,10);
		}

	private:
		T* _a;
	};

}

void test_template_instantiation()
{
	me::A<int> a;
	a.func1();

}

a、上述代码明显是错误的

b、只调用func1运行没有问题

c、调用func2就会出问题

四、模板特化


1、函数模板特化


a、定义


模板传具体的类型A
template<>
bool func(A a1, A a2)
{...}

b、理解


模板的行为不符合我们的预期
例如,模板的比较都是对具体的整型x和y进行比较,然后返回结果
但是,现在我需要用地址比较
也就是要比较*x和*y
但是原模板比较的依旧是x和y,如果不解引用就变成了比较地址
这个时候,原来模板不能处理
所以,需要针对特殊类型进行特殊处理
只能写一个
那么我们写的这个,不是模板
而是区别于模板的特殊类,所以叫做特化
本质是对函数模板的重载

2、类模板特化


模板是匹配,不是替换

a、定义格式

1)类模板
//类模板
template<class T1,class T2>
class A
{
public:

	A()
	{
		cout <<"A<T1,T2>" << endl;
	}
private:
	T1 _a;
	T2 _b;
};
2)半特化/偏特化

//半特化/偏特化
template<class T>
class A<T,char>
{
public:
	A()
	{
		cout << "A<T,class>" << endl;

	}
};
3)全特化

//全特化
template<>
class A<int ,int >
{
public:
	A()
	{
		cout << "A<int,int>" << endl;
	}
};
4)按需调用


b、理解

和函数模板的理解是一样的
依旧是类模板的行为不符合我们的预期


五、模板声明定义分离

1、不支持声明定义分离

a、为什么?

如果定义分离,那么声明在头文件,定义在实现文件

一个程序的运行需要经过:预处理、编译、链接三个阶段
模板是在编译阶段的时候实例化
在编译阶段是没有链接的,即各个文件是独立的,没有联系的
那么,在编译模板的时候
头文件有声明,但是没有定义
实现文件有定义,但是它不知道要怎么实例化!
就是我不知道你模板要实例化成什么
而模板的原则是按需实例化
所以,这就导致了模板没有进行实例化

那么到了链接的时候,去找模板定义的时候,找不到

b、解决办法?

有解决办法吗?没有,这是设计机制的问题
但是其实还可以显式实例化
就是在定义文件再写一个声明,告诉模板要实例化成什么
但是,这纯粹是蛋疼家才会选择的方式
所以,闲着没事就不要声明定义分离了

六、模板的优缺点

1、优点

a、代码更加灵活

b、模板复用了代码,节省了很多自己写代码的时间

2、缺点

a、代码膨胀,编译时间变长

b、如果出现错误,不好定位,因为不知道到底是那个实例化出的问题,需要逐个排除

相关推荐

  1. C++:模板

    2024-05-05 01:02:01       47 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-05 01:02:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-05 01:02:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-05-05 01:02:01       87 阅读
  4. Python语言-面向对象

    2024-05-05 01:02:01       96 阅读

热门阅读

  1. QT, 系统托盘 及 菜单

    2024-05-05 01:02:01       33 阅读
  2. 我用过的最好用的 AI 工具

    2024-05-05 01:02:01       34 阅读
  3. 【博弈游戏】

    2024-05-05 01:02:01       27 阅读
  4. 第二十六章 版本管理 - GIT

    2024-05-05 01:02:01       43 阅读
  5. 代码随想录算法训练营day56

    2024-05-05 01:02:01       32 阅读
  6. Linux上OcenBase单机版部署及基本信息查询

    2024-05-05 01:02:01       36 阅读