typename关键字
typename是一个c++关键字,主要用于解决模板定义中的依赖类型名称的解析问题。它告诉编译器紧随其后的名称是一个类型,而不是静态成员或成员函数。在模板编程中正确使用typename是理解和编写复杂模板代码的关键。
那什么是模板定义中的依赖类型名称的解析问题?下面我通过一个样例带大家看看。假设我需要写一个遍历容器的打印函数Print()。
由于在Print函数第一行没有明确的告知编译器Container是对象还是类型。所以,编译器直接报错。解决方法也很简单,就是在Container前加上typername修饰一下,告诉编译器,你大胆实例化,这个模板是类型。然后,编译器就会在实例化的时候去找。
当然,使用auto关键字也可以解决这样的问题。因为,auto关键字就是类型,它是通过 = 右边的内容去推导类型。
typename的使用事项
typename只能用于模板定义中,并且紧跟在依赖类型名称之前。
在模板定义之外,当类型已经明确时,不需要使用typename。这也是为什么在前面的学习中没有提到它。
typename不能用于基础类型(如int、float等)或指针类型(如int*)之前,因为这些类型不是依赖于模板参数的。
在模板声明中,即使类型依赖于模板参数,通常也不需要使用typename(但在某些复杂的模板元编程场景中可能会用到)。
在模板声明中,typename和class作为模板类型参数的关键字是等价的,可以互换使用。然而,在指示依赖类型名称时,只能使用typename。
与class的区别
在模板声明中,typename和class作为模板类型参数的关键字是等价的,可以互换使用。然而,在指示依赖类型名称时,只能使用typename。
非类型模板参数
非类型模板参数是一个模板的特性。它允许模板定义时不仅接受类型作为参数,还可以接受常量表达式作为参数。这些常量表达式可以是整型(包括字符、枚举和指针)、引用以及用户定义类型的对象(需要满足常量性和可链接性要求)。
它的出现解决了C语言在对象定义时给定一个常量决定静态数组的长度。
给静态栈加一个非类型模板参数即可,需要注意的这个常量不能在实例化后被修改。
array的简单介绍
array是C++11更新时更新的一个新容器,它就带有非类型模板参数。它的使用逻辑与原生数组以及vector大差不差,这里简单演示一下它的使用。
它像原生数组那样并不会直接初始化,需要咱们手动初始化。它相较于原生数组提供了更严格的边界检查。这是因为它重载了operator[]。
整体来说,这个容器还是比较鸡肋。它既不如原生数组贴近底层并且纯粹,又不如vector来的强大。整体还是被吐槽的挺多的。
模板的特化
函数模板特化
函数模板特化是C++泛型编程的一种技术,它帮助我们实现特定类型或一组类型提供函数模板的实现。函数模板的特化只能全特化。下面我就通过一个简单的样例介绍一下它是什么样的。
需要注意,函数模板的特化必须和原始函数模板在功能上保持逻辑的一致性以及连贯性,避免产生冲突。同时,特化函数模板不能独立于原始函数模板存在。
类模板特化
类模板特化就是对特定类型或一组类型提供类的特殊化实现。具体有全特化和片特化之分。下面先给大家介绍一下语法。
下面在通过一个样例带大家感受一下特化。在上篇文章中,我们在测试priority_queue对于自定义类型Date的指针处理上,重新实现了仿函数进行控制。现在通过片特化默认的仿函数感受一下。
下面简单谈一谈类模板特化的限制。特化模板类必须和原始模板类在同一个命名空间下,并且特化版本和原始版本的模板参数列表和函数形参列表需要一致。
最后,谈一谈类模板特化和函数模板特化的区别。类模板特化是针对整个类进行的,包括成员函数和成员变量。而函数模板特化只能针对特定的数据类型的函数进行特殊化处理,且特殊化版本的形参列表必须和原始版本的一致。
模板分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
下面以一个场景带大家看看模板的分离编译所产生的问题。
这里的调试报错报的是链接错误,找不到push、pop函数的地址。
为了避免这种情况的发生,需要对模板函数定义的位置进行显示实例化。
当然,对于类模板还是建议声明和定义都放在一个.h或.hpp文件中。尽量避免跨文件使用模板分离编译。同一个文件里声明和定义分离是没啥问题的,像STL库就是这样实现的。
总结
模板的出现大大的增强了编程的灵活性。比如仿函数、适配器等。更重要的是大大增加了代码的复用性,提高了开发的迭代效率,STL库也因为模板的出现孕育而生。再谈一谈模板的缺点。模板的出现延长了编译的时间,当然了不可避免,因为程序员把更多的活给了编译器干。以及模板报错信息又长又乱,非常难以定位错误,这也更考验程序员用经验来解决报错问题。