关键字②:typename

typename

typename作为关键字有以下的用法:

  • 作为模板元编程使用

template <typename T> 
template <class T>

void foo(const T& t)
{   
    // 声明一个指向某个类型为T::bar的对象的指针
    typename T::bar * p;
}

typename的作用其实和class的作用的一致的,是class的替换(class并不是指的C++中的类Class),它是一种类型名,不是变量名,为了能够更好的理解和编写代码,而添加的一个关键字。

  • 作为类型名的声明(至少写者是这么认为)

template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

粗略一看,T::iterator可能是模板T中的一个变量(如枚举变量),可能是结构体,也可能是某种类型,这一操作似乎就是定义一个指针变量iter,这么想是没错的,但实际上是错误的。

在探索错误的原因前,我们应该知道T::iterator实际上可以是以下三种中的任何一种类型:

  • 静态数据成员
  • 静态成员函数
  • 嵌套类型

回到错误上来,如果说iterator是嵌套类型,这个写法完全是没有问题,但iterator是静态数据成员呢?此时就会出现问题,这个时候的T::iterator * iter就变成了一个乘法表达式了。

此时,解决的办法就是在T::iterator * iter前添加typename关键字,以此来表示T::iterator是一个类型,同样也称为嵌套依赖名字(nested dependent name);通用的规则很简单:在你涉及到一个在 template(模板)中的嵌套依赖类型名( nested dependent type name)的任何时候,你必须把单词 typename 放在紧挨着它的前面。

template <typename T>

void f(const T &t,typename T::iterator &iter){
    ......
}

上述代码中,t不是一个嵌套类型名(它不是嵌套在依赖于一个 template parameter(模板参数)的什么东西内部的),所以不必添加typename关键字;而T::iterator * iter是一个嵌套类型名,故需要添加该关键字。

  • 使用typename的规则

  • typename在下面情况下禁止使用:
    • 模板定义之外,即typename只能用于模板的定义中;
    • 非限定类型,比如前面介绍过的intvector<int>之类,即一开始就标注了类型;
    • 基类列表中,比如template<class T> class C1 : T::InnerType不能在T::InnerType前面加typename;
    • 构造函数的初始化列表中;
  • 如果类型是依赖于模板参数的限定名,那么在它之前必须加typename(除非是基类列表,或者在类的初始化成员列表中);
  • 其它情况下typename是可选的,也就是说对于一个不是依赖名的限定名,该名称是可选的,例如vector<int> vi
typedef typename T::iterator iterator_type;

则现在,我们就能够懂得这样的定义具体的意思是什么了。

参考

  1. C++ Primer
  2. C++中typename关键字的使用方法和注意事项
  3. C++箴言:理解typename的两个含义
发布了90 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_37160123/article/details/93487899