zoukankan      html  css  js  c++  java
  • 读书笔记_Effective_C++_条款四十二:了解typename的双重意义

    顾名思义,typename有双重含意。只要你用过template,那么第一重含意一定知道,那就是声明模板的时候,我们既可以这样写:

     template <class T> 

    也可以这样写

     template <typename T> 

    这两种写法并没有任何区别,都是标记T可以是符合隐式接口的任何类型,包括系统预定义类型,也包括用户自定义类型。

    typename的第二重含意其实不大能遇到,因为这个依赖于编译器,看下面的例子:

     1 class SampleClass
     2 {
     3 public:
     4     typedef int MyInt;
     5 // static const int MyInt = 3;
     6 };
     7 
     8 int main()
     9 {
    10     SampleClass::MyInt *b = new int(3); // 有的编译器会报错
    11 }

    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有两个特例,一个是继承的时候,像下面这样:

    1 class A: public B::NestedClass{}; // 正确
    2 class A: public typename B::NextedClass(){}; // 错误

    在继承XXX类时,即使这个类名是dependent names,也不要使用typename,因为编译器这时候显示不会将之翻译成静态成员(被继承类必定是个类型)。

    另一个特例是构造函数时,对于构造成员列表,像下面这样:

    1 A(): B::NestedClass(){} // 正确
    2 A(): typename B::NestedClass(){} // 错误

    这时候编译器也不会将之视为静态对象的,因为静态对象是不支持成员初始化列表这样的初始化形式的,所以这时的typename,反而会被编译器认为一个是BUG。

    最后总结一下:

    1. 声明template参数时,前缀关键字class与typename可以互换

    2. 请使用关键字typename标识嵌套从属类型名称;但不得在base class lists或者member initialization list内使用typename

  • 相关阅读:
    【强行点出机械师天赋,修复无脸男储钱罐】
    【自由随想录(二)】
    【自由随想录(一)】
    iOS Alamofire插件使用方法
    iOS获取设备ip地址(OC版)
    获取位置
    objective-c 开发最简单的UITableView时数据进不去的问题
    java 获取真实IP
    数据库添加外键
    mysql 清库
  • 原文地址:https://www.cnblogs.com/jerry19880126/p/3622191.html
Copyright © 2011-2022 走看看