C++ typename详解
博客:https://goodfanqie.github.io(文章优先展示地方,推荐在此阅读。)
typename的疑问
最近在学习《STL 源码剖析》这本书的时候,在里面看到其中关于typename的用法令我非常的疑惑。
typedef typename _type_traits<T>::has_trivial_destory trivial_destructor;
看到这行代码的时候我疑惑得去数了一下这中间的空格数,因为在印象中,typedef的用法是原类型名加新类型名,但是这里多出来的typename让我觉得很疑惑,后面查阅了很多资料翻了很多博客才慢慢想清楚了这其中的原因。我们先撇开后面跟的那一大串type_traits不谈,因为这个需要单独一篇博客才讲得清楚。我们先从简单的例子开始。
typename的最常用法
typename通常用于在模版的定义中,如下:
template <typename T> class Test;
template <class T> class Test2;
在上述定义中,对于C++本身来说,typename和class是完全没有区别的。但是对于C++来说这样有什么好处吗,为什么要造两个意义一样的关键字,我们从他们的起源开始。
对于一些更早接触C++的朋友,你可能知道,在C++标准还未统一时,很多旧的编译器只支持class,因为那时C++并没有typename关键字。记得我在学习C++时就曾在某本C++书籍上看过类似的注意事项,告诉我们如果使用typename时编译器报错的话,那么换成class即可。
一切归结于历史。
Stroustrup在最初起草模板规范时,他曾考虑到为模板的类型参数引入一个新的关键字,但是这样做很可能会破坏已经写好的很多程序(因为class已经使用了很长一段时间)。但是更重要的原因是,在当时看来,class已完全足够胜任模板的这一需求,因此,为了避免引起不必要的麻烦,他选择了妥协,重用已有的class关键字。所以只到ISO C++标准出来之前,想要指定模板的类型参数只有一种方法,那便是使用class。这也解释了为什么很多旧的编译器只支持class。
class在模版中遇到的麻烦
我们谈到,Stroustrup在准备引入新关键字的时候,class在当时似乎已经完全胜任了模版对象的这一个需求,但是在越来越多的实践过程中,class的缺点或者说template的缺点出现了。
假设你现在要针对某一种容器设定一个操作函数:
template <class T>
void func (){T::iteartor * testpt;
}
看到这段代码的时候我们大多数情况下都是可以看出来,这一段代码中的操作是定义了一个容器的迭代器指针类型的变量。但是模版是在编译期间展开的,只有在模版实例化的时候编译器才可以推导出其类型。这段代码对于编译器来说很有可能产生错误的理解,因为我们能快速的根据iteartor是一个迭代器想到这是定义了一个变量,但是对于编译器来说,它怎么会知道一定知道T::iteartor一定是一个迭代器类型,或者一定知道这是一个类型?因为能表示成这样形式的代码有三种情况:
- 在T作用域中存在一个iteartor的静态变量
- 在T作用域中存在一个iteartor的静态成员函数
- 是T类型的成员变量
以上三种含义均可以表示成例子中的样子,编译器怎么知道这是哪一种。在实践过程中,编译器会直接对testpt报错:
error: use of undeclared identifier 'testpt'
typename的真正用途
编译期间模版的推导有一个这样的规则:如果解析器在template推导期间遇到了嵌套从属名称,那么不指定他为一个类型,解析器就一定不会把它当成一个类型。什么是从属类型,就是形如T::iteartor
这种,这也就是为什么编译器会对testpt报错的原因。那要怎样指定testpt为一个类型,这就回到了开头的那个问题,我们可以这样解决:
template <class T>
void func (){typename T::iteartor * testpt;
}
加上了typename之后我们就可以知道T::iteartor是一个类型,编译器也可以根据这个进行类型推导了。
C++ typename详解相关推荐
- C++typename详解
C++typename详解 typename的常见用法 类作用域 完整例子 剖析源码 STL底层源码有下面几行,typedef与typename联用,这几个看着好复杂,究竟啥意思,我们今天一起来剖析! ...
- template类的typename详解--龙之介《Effective C++》实验室
条款typename的双重定义 声明关键字class和typename可互换 假设你这样声明一个迭代器 C::const_iterator iter(container.begin()); 这将不是一 ...
- 【OpenCV 4开发详解】深度神经网络应用实例
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...
- 【数据结构】堆,大根堆,小根堆,优先队列 详解
目录 堆 1.堆的数组实现 2.小根堆 3.大根堆 4.优先队列 例题 1.SP348 EXPEDI - Expedition(有趣的贪心思路,优先队列) 2.合并果子 堆 要了解堆之前,请先了解树, ...
- 【查询】—Entity Framework实例详解
Entity Framework 查询使用集成查询,简称LINQ.LINQ是一个查询框架,并不限于Entity Framework使用,同样不限于数据库.LINQ Provider 负责将LINQ查询 ...
- 基础排序算法详解与优化
文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...
- 26.C++- 泛型编程之类模板(详解)
在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板 类模板介绍 和函数模板一样,将泛型思想应用于类. 编译器对类模板处理方式和函数模板相同,都是进行2次编译 类模板通 ...
- C++模板之特化与偏特化详解
2019独角兽企业重金招聘Python工程师标准>>> C++函数模板与类模板实例解析_C 语言_脚本之家 http://www.jb51.net/article/53746.htm ...
- shell中的mput_FTP命令详解 及 shell中的使用
FTP命令详解 FTP的命令格式为:ftp-v-u-d-i-n-g[IP地址]-v显示远程服务器的所有响应信息(verbose:详细,繁冗)-n限制ftp的自动登录,即不使用-d使用调试方式(debu ...
最新文章
- oracle rman异机恢复
- 选择云备份:应当怎样和云供应商签合同
- Android怎么实现选课功能,选课系统android
- UVa810 A Dicey Problem 筛子难题
- J2EE搭建Dynamic web SpringMVC工程404错误分析(一)
- python 常用镜像
- Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用
- SpringBoot 集成 Nacos
- 少走弯路的10个忠告
- JEECG参与2017年度最受欢迎开源项目投票,请投上宝贵一票
- 自定义iOS7导航栏背景,标题和返回按钮文字颜色
- 更改Fedora 11的plymouth开机动画
- kettle预览点两下才出数_谁才是娱乐圈油腻王中王?
- resizableImageWithCapInsets:方法的探析 (转载笔记)
- Jmeter插件安装及使用
- 学习OpenCV——SVM 手写数字检测
- 浅层砂过滤器(浅层介质过滤器)介绍及现场案例反馈图(多图)
- Java课程设计题目七:魔板游戏
- 0基础前端开发,html5建站教程
- 不同产品生命周期的营销策略