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

  • 相关阅读:
    [CF1355] Codeforces Round #643 (Div. 2)
    [ABC189] AtCoder Beginner Contest 189
    P3702 [SDOI2017]序列计数 (三模数NTT)
    P3321 [SDOI2015]序列统计 (NTT快速幂)
    洛谷P4157 [SCOI2006]整数划分
    洛谷P2553 [AHOI2001]多项式乘法
    洛谷P1919 (模板)A*B Problem升级版(FFT快速傅里叶)
    MySQL学习总结-详细版(包括下载安装)
    查看oracle数据库中表是否被锁
    SQL优化(面试题)
  • 原文地址:https://www.cnblogs.com/jerry19880126/p/3622191.html
Copyright © 2011-2022 走看看