博客: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详解相关推荐

  1. C++typename详解

    C++typename详解 typename的常见用法 类作用域 完整例子 剖析源码 STL底层源码有下面几行,typedef与typename联用,这几个看着好复杂,究竟啥意思,我们今天一起来剖析! ...

  2. template类的typename详解--龙之介《Effective C++》实验室

    条款typename的双重定义 声明关键字class和typename可互换 假设你这样声明一个迭代器 C::const_iterator iter(container.begin()); 这将不是一 ...

  3. 【OpenCV 4开发详解】深度神经网络应用实例

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  4. 【数据结构】堆,大根堆,小根堆,优先队列 详解

    目录 堆 1.堆的数组实现 2.小根堆 3.大根堆 4.优先队列 例题 1.SP348 EXPEDI - Expedition(有趣的贪心思路,优先队列) 2.合并果子 堆 要了解堆之前,请先了解树, ...

  5. 【查询】—Entity Framework实例详解

    Entity Framework 查询使用集成查询,简称LINQ.LINQ是一个查询框架,并不限于Entity Framework使用,同样不限于数据库.LINQ Provider 负责将LINQ查询 ...

  6. 基础排序算法详解与优化

    文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...

  7. 26.C++- 泛型编程之类模板(详解)

    在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板   类模板介绍 和函数模板一样,将泛型思想应用于类. 编译器对类模板处理方式和函数模板相同,都是进行2次编译 类模板通 ...

  8. C++模板之特化与偏特化详解

    2019独角兽企业重金招聘Python工程师标准>>> C++函数模板与类模板实例解析_C 语言_脚本之家 http://www.jb51.net/article/53746.htm ...

  9. shell中的mput_FTP命令详解 及 shell中的使用

    FTP命令详解 FTP的命令格式为:ftp-v-u-d-i-n-g[IP地址]-v显示远程服务器的所有响应信息(verbose:详细,繁冗)-n限制ftp的自动登录,即不使用-d使用调试方式(debu ...

最新文章

  1. oracle rman异机恢复
  2. 选择云备份:应当怎样和云供应商签合同
  3. Android怎么实现选课功能,选课系统android
  4. UVa810 A Dicey Problem 筛子难题
  5. J2EE搭建Dynamic web SpringMVC工程404错误分析(一)
  6. python 常用镜像
  7. Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用
  8. SpringBoot 集成 Nacos
  9. 少走弯路的10个忠告
  10. JEECG参与2017年度最受欢迎开源项目投票,请投上宝贵一票
  11. 自定义iOS7导航栏背景,标题和返回按钮文字颜色
  12. 更改Fedora 11的plymouth开机动画
  13. kettle预览点两下才出数_谁才是娱乐圈油腻王中王?
  14. resizableImageWithCapInsets:方法的探析 (转载笔记)
  15. Jmeter插件安装及使用
  16. 学习OpenCV——SVM 手写数字检测
  17. 浅层砂过滤器(浅层介质过滤器)介绍及现场案例反馈图(多图)
  18. Java课程设计题目七:魔板游戏
  19. 0基础前端开发,html5建站教程
  20. 不同产品生命周期的营销策略

热门文章

  1. STM32F103xx OLED旋转显示图片
  2. LOG高斯-拉普拉斯算子
  3. Websocket系列 -- 协议详解
  4. 如何保证同事的代码不会腐烂?一文带你了解 Alibaba COLA 架构
  5. string转LPCTSTR
  6. Spring 教程(一)
  7. Unity Bolt插件 基本使用
  8. php 实现无限极分类详解
  9. 数商云智慧医疗管理系统解决方案:医药电商系统实现智能化改造
  10. 笔记-首次参加数据挖掘比赛摸索的经验(赛题为CCF-BDCI2017企业经营退出风险预测)