依赖类型,顾名思义就是依赖于模板参数的类型,在使用这种类型时,必须使用 typename,否则编译器是无法知道是在使用类型,还是类的成员(因为类的静态成员的使用方法也是T::xxx,这跟某个类中的类型的使用方法是一样的)。
下面看一下简单的例子:
#include <stdio.h>
#include <stdlib.h>
struct myData
{
typedef unsigned int myType;
myType mValue;
myData()
{
mValue = 100;
}
};
template <typename T>
int func(const T &it)
{
T::myType value = 200;
return it.mValue - value;
}
int main()
{
myData data;
myData::myType ret = func(data);
printf("ret = %d\n", ret);
}
在这个模板函数 func 中想要使用 myData::myType 这个类型来声明一个变量 value,这样编译会出现什么错误呢?
编译错误已经指明,需要使用 typename 来引用T::myType 这个类型,因为T是一个依赖作用域。假如不用 typename 也能编译成功的话,是不是就会产生歧义了?因为 T::myType 也可以表示为一个类的静态成员,所以 typename 是必要的。 所以要想使用依赖于模板参数的类型时,必须加上 typename,如:typename T::myType value = 200;
如《Effective STL》中的例子
template<typename C>
bool lastGreaterThanFirst(const C& container)
{
if (container.empty()) return false;
typename C::const_iterator begin(container, begin());
typename C::const_ierator end(container.end());
return *--end > *begin;
}
在这个例子里,局部变量begin和end的类型是C::const_iterator。const_iterator是依赖形式类型参数C的一种类型。因为C::const_iterator是一种依赖类型,你被要求在它之前放上 typename 这个词。(一些编译器错误地接受没有typename的代码,但这样的代码不可移植。)