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是一个类型,编译器也可以根据这个进行类型推导了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值