读书笔记_Effective_C++_条款四十二:了解typename的双重意义
顾名思义,typename有双重含意。只要你用过template,那么第一重含意一定知道,那就是声明模板的时候,我们既可以这样写:
template <class T>
也可以这样写
template <typename T>
这两种写法并没有任何区别,都是标记T可以是符合隐式接口的任何类型,包括系统预定义类型,也包括用户自定义类型。
typename的第二重含意其实不大能遇到,因为这个依赖于编译器,看下面的例子:
class SampleClass
{
public:
typedef int MyInt;
// static const int MyInt = 3;
}; int main()
{
SampleClass::MyInt *b = new int(); // 有的编译器会报错
}
MyInt来源于SampleClass内的一个重定义,MyInt等价于int,所以main函数里面实质上是int *b = new int (3),但有的编译器会报error,这是因为编译器在遇到这句代码上会产生歧义,因为它可以将MyInt作为SampleClass的一个静态对象来看(可以看程序被注释掉的代码的地方),这样就变成了一个静态对象乘以b了。这种“看法”有些不可思议,但在有些编译器上,却是优先将之视为静态变量的,而不是类型。为了解决这个二义性,在前面加上typename,这样就会强制让编译器将之视为一个类型,而不是静态变量了。像这种SampleClass::MyInt或是书上举的T::const_iterator,都是类中定义的名字,这种名字称之为dependent names(嵌套从属名称),所有dependent names都潜在具有二义性,为了消除二义性,就在前面加上typename,变成typename T::const_iterator,typename SampleClass:MyInt,这样就会解决一些看似正确却怎么也编不过的代码问题了。
使用typename有两个特例,一个是继承的时候,像下面这样:
class A: public B::NestedClass{}; // 正确
class A: public typename B::NextedClass(){}; // 错误
在继承XXX类时,即使这个类名是dependent names,也不要使用typename,因为编译器这时候显示不会将之翻译成静态成员(被继承类必定是个类型)。
另一个特例是构造函数时,对于构造成员列表,像下面这样:
A(): B::NestedClass(){} // 正确
A(): typename B::NestedClass(){} // 错误
这时候编译器也不会将之视为静态对象的,因为静态对象是不支持成员初始化列表这样的初始化形式的,所以这时的typename,反而会被编译器认为一个是BUG。
最后总结一下:
1. 声明template参数时,前缀关键字class与typename可以互换
2. 请使用关键字typename标识嵌套从属类型名称;但不得在base class lists或者member initialization list内使用typename
读书笔记_Effective_C++_条款四十二:了解typename的双重意义的更多相关文章
- 读书笔记_Effective_C++_条款三十二:确定你的public继承继承塑模出is-a关系
这一条款是说的是公有继承的逻辑,如果使用继承,而且继承是公有继承的话,一定要确保子类是一种父类(is-a关系).这种逻辑可能与生活中的常理不相符,比如企鹅是生蛋的,所有企鹅是鸟类的一种,直观来看,我们 ...
- 读书笔记_Effective_C++_条款四十九:了解new_handler的行为
本章开始讨论内存分配的一些用法,C/C++内存分配采用new和delete.在new申请内存时,可能会遇到的一种情况就是,内存不够了,这时候会抛出out of memory的异常.有的时候,我们希望能 ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- 读书笔记_Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数
这个条款可以看成是条款24的续集,我们先简单回顾一下条款24,它说了为什么类似于operator *这样的重载运算符要定义成非成员函数(是为了保证混合乘法2*SomeRational或者SomeRat ...
- 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...
- 读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template
标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况. 假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对 ...
- 读书笔记_Effective_C++_条款四十:明智而审慎地使用多重继承
多重继承是一种比较复杂的继承关系,它意味着如果用户想要使用这个类,那么就要对它的父类也了如指掌,所以在项目中会带来可读性的问题,一般我们都会尽量选择用单继承去替代它. 使用多重继承过程容易碰到的问题就 ...
- 读书笔记_Effective_C++_条款三十:了解inline的里里外外
学过基本程序课的同学都知道,inline是内联的关键字,它可以建议编译器将函数的每一个调用都用函数本体替换.这是一种以空间换时间的做法.把每一次调用都用本体替换,无疑会使代码膨胀,但可以节省函数调用的 ...
- 读书笔记_Effective_C++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句话是:普通函数既继承接口,也强制继承 ...
随机推荐
- 构建单页Web应用
摘自前端农民工的博客 让我们先来看几个网站: coding teambition cloud9 注意这几个网站的相同点,那就是在浏览器中,做了原先“应当”在客户端做的事情.它们的界面切换非常流畅,响应 ...
- Zabbix学习笔记一:基本安装与配置
1.下载安装 http://120.52.73.43/tenet.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/3.0.1/za ...
- paip.不同目录结构哈的文件批量比较
paip.不同目录结构哈的文件批量比较 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/att ...
- 在php中,如何将一个页面中的标签,替换为用户想输出的内容
前言:釜山行,暴露人性, ———————————————————————————————————————————————————————————————————————————— 今天说一个最简单的例 ...
- hdu 1385 Minimum Transport Cost (floyd算法)
貌似···················· 这个算法深的东西还是很不熟悉!继续学习!!!! ++++++++++++++++++++++++++++ ======================== ...
- Parallel的陷阱
,).ToArray(); ; Parallel.For<int>( fromInclusive: , toExclusive: nums.Length, /* 陷阱 */ localIn ...
- 实现多项式的JAVA类
p = coef[i] + (x * p); } Poly ...
- 查看Exchange邮件队列(queue)
#加载Exchange管理模块 Add-PSSnapin Microsoft.Exchange.Management.PowerShell.snapin get-queue #查看队列 get-mes ...
- S7-200系列PLC与WINCC以太网通信CP243i的实例
S7-200系列PLC与WINCC以太网通信CP243i的实例 ----选用大连德嘉国际电子www.dl-winbest.cn的CP243i作为连接S7-200的PPI口转以太网RJ45的接口转换器. ...
- 在ps中画两个同心圆并且把两个同心圆进行任意角度切割
在工作中遇到要在ps中画如图两个同心圆,并且进行6等分.查找资料加自己摸索,可以通过以下方式实现: 1.新建一画布.并用通过标尺画出两条水平和垂直参考线,选择椭圆工具,并在选项设置中选择圆和从中心两个 ...