前言:
typename关键字是我们学习模板的时候,了解到的一个关键字。但在这几天之前,也仅仅是了解到有这个关键字,而几乎不用这个关键字。在个人看来,在template的参数中,由于class的存在这个简单的关键字,使typename变得有些暗淡。
而在这几天的一句代码中,才让我迫不及待的了解这个关键字。
这是一句什么代码呢?,让我们看正文!
typename关键字
typedef typename Hash::hash_iterator<K, std::pair<K, V>, MapKeyofT<K, V>,Ha> iterator;
在我不太了解typename关键字之前,也就是只知道在template参数中可以用typename,所以我写的代码是:
typedef Hash::hash_iterator<K, std::pair<K, V>, MapKeyofT<K, V>,Ha> iterator;
而这个时候,代码编译一直通不过 。
那么通不过的原因是什么呢?
在此之前我们需要了解一些概念。从属名称和非从属名称
//此处代码只是为了让大家了解概念
template <class T>
void vectorPrintf(vector<T>& arr)
{
vector<T>::iterator it=arr.begin();
while(it!=arr.end())
{
int x=*it;
++it;
cout<<x<<endl;
}
}
template内出现的名称如果依存于某一个template参数,称之为从属名称。
如果从属名称在class内称嵌套状,我们称它为嵌套从属名称
一个并不依赖任何template参数的名称,这样的名称就是非从属名称
it的类型是什么取决于template的参数T,则这就是一个从属名称,并且它还是一个嵌套名称。
x的类型为int,和template的参数没有任何关系,这就是一个非从属名称。
我们再了解概念之后,直接给出typename的用处:
typename 的用处:
- 用于声明template中的参数,从C++角度来看,无论使用typename还是class,意义都是相同的
- typename被用来验明嵌套从属类型名称,其他名称不需要有它
template<class C> //声明template的参数,template和class意义相同,看个人习惯选择使用
void Fun(C& container, //非嵌套从属类型名称,不需要使用typename
typename C::iterator it) //嵌套从属类型名称,一定要使用typename
用typename检验嵌套从属类型名称,这出于一种现状:嵌套名称有可能导致解析困难
C::iterator * x
我们看起来是申请了一个指针变量x 类型为C::iterator 。但是如果C中有个static变量命名为iterator,这句代码就和我们想的效果,相距十万八千里了,并且让我们感觉到这个世界太疯狂:两个变量进行相乘。
C++中有个规则,我们可以用这个理解一下,当解析器到这句代码的时候,不知道C::iterator是一个嵌套从属名称,怎么办呢?它就假设这不是一个类型,也就产生了我们刚才奇幻的一幕,被认为是两个变量相乘!而解决办法就是你告诉解析器这是一个嵌套从属名称,那么所遇到的问题也就迎刃而解了!
我们对于typename的认识到这里应该就完全OK了,但是这个世界总是有一些特别的事物,吸引着我们
请使用关键字typename表示嵌套从属类型名称;但不得在基类列表或者成员初始列表内以它作为基类的修饰符
template<class C> //声明template的参数,template和class意义相同,看个人习惯选择使用
class Derived : public Base<C>::xx //基类列表,不允许使用typename
{
Derived(int x)
: Base<C>::xx(x)
{
C& container //非嵌套从属类型名称,不需要使用typename
Base<C>::xx tmp //嵌套从属类型名称,一定要使用typename
}
}
让我们再次回顾一下typename
- 用于声明template中的参数,从C++角度来看,无论使用typename还是class,意义都是相同的
- 请使用关键字typename表示嵌套从属类型名称;但不得在基类列表或者成员初始列表内以它作为基类的修饰符
本文参考于Effective C++
注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!