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,这么想是没错的,但实际上是错误的。
在探索错误的原因前,我们应该知道实际上可以是以下三种中的任何一种类型:
- 静态数据成员
- 静态成员函数
- 嵌套类型
回到错误上来,如果说iterator是嵌套类型,这个写法完全是没有问题,但iterator是静态数据成员呢?此时就会出现问题,这个时候的就变成了一个乘法表达式了。
此时,解决的办法就是在前添加typename关键字,以此来表示是一个类型,同样也称为嵌套依赖名字(nested dependent name);通用的规则很简单:在你涉及到一个在 template(模板)中的嵌套依赖类型名( nested dependent type name)的任何时候,你必须把单词 typename 放在紧挨着它的前面。
template <typename T>
void f(const T &t,typename T::iterator &iter){
......
}
上述代码中,不是一个嵌套类型名(它不是嵌套在依赖于一个 template parameter(模板参数)的什么东西内部的),所以不必添加typename关键字;而是一个嵌套类型名,故需要添加该关键字。
-
使用typename的规则
- typename在下面情况下禁止使用:
- 模板定义之外,即typename只能用于模板的定义中;
- 非限定类型,比如前面介绍过的
int
,vector<int>
之类,即一开始就标注了类型; - 基类列表中,比如
template<class T> class C1 : T::InnerType
不能在T::InnerType
前面加typename; - 构造函数的初始化列表中;
- 如果类型是依赖于模板参数的限定名,那么在它之前必须加typename(除非是基类列表,或者在类的初始化成员列表中);
- 其它情况下typename是可选的,也就是说对于一个不是依赖名的限定名,该名称是可选的,例如
vector<int> vi
;
typedef typename T::iterator iterator_type;
则现在,我们就能够懂得这样的定义具体的意思是什么了。
参考