typeneme的双重意义!
—–effective c++ item42.
typename和class在template声明式中,并没有什么不同.
template<class T> class Foo;
template<typename T> class Goo;
从c++角度看,声明template时,不论使用关键字class或者typename,他们的意义完全相同.
嵌套从属类型名称
template 内出现的名称如果相依于某个template参数,就称它为从属名称(dependent names). 如果从属名称在class 内成嵌套状,它就是嵌套从属名称(nested dependent name).
并不好理解….还是先考虑下面的代码.
// 错误的代码..不能通过编译
// print_2nd接受stl容器为参数,并打印第二个元素的值.
template<typename T>
void print_2nd(const T &container) // 接受stl容器为参数
{
if(container.size() >= 2) {
T::const_iterator iter(container.begin()); // iter的类型取决于T的类型,因此iter是从属名称.
iter++;
int value = *iter;
std::cout << value << std::endl;
}
}
上面的代码中,iter实际上是一个嵌套从属类型名称.而它的类型T::const_iterator则是嵌套从属类型名称(nested dependent type name),也就是个嵌套从属名称并且指向某类型.
print_2nd()内的另一个本地变量value,它的类型是int. int 不依赖任何template参数的名称.这样的名称是谓非从属名称(non-dependent names)…Sott Meyers觉得应该叫它..独立名称(independent names)…
现在再来看看为什么编译器不通过上面的代码
当编译器开始解析template print_2nd时,并不知道T是什么东西.这是因为c++在解析模板中遇到一个嵌套从属名称,它便假设这名称不是个类型,除非你告诉它是.所以默认下嵌套从属类型不是类型.
因此只有iter的声明时指出T::const_iterator是个类型时才合理.解决方法就是在T::const_iterator前加上typename.
改正后的代码:
template<typename T>
void print_2nd(const T &container)
{
if(container.size() >= 2) {
typename T::const_iterator iter(container.begin());
iter++;
int value = *iter;
std::cout << value << std::endl;
}
}
模板类中的typename
看起来好像只要涉及嵌套从属名称就应该给它的前面加上typename指明它是个类型.不过当然也有例外.
typename不可以出现在基类列表(base classes list)和成员初始化列表(member initialization list)中作为基类修饰符.
例如:
template<typename T>
class Son : public Base<T>::mem
{
public:
explicit Son(int x)
: Base<T>::mem(x)
{
typename Base<T>::mem grand; // 这里必须使用
}
};
不同的编译器对待typename
typename的相关规则在不同的编译器上有不同的实践.某些编译器接受的代码原本该有typename却遗漏了;原本不该有typename却出现了.这意味者typename和嵌套从属名称的互动,在移植上会有让人头疼的一面..