Effective C++ 条款42 了解typename的双重意义
1. 在template的声明式中,typename的使用和class完全相同,即以下两种声明方式完全相同
template<typename T> template<class T>
然而typename还有其他用途:指明嵌套从属类型名称.
2. 嵌套从属类型名称:如果template中某个名称依赖于类型参数,那么它就是从属名称,如果这个从属名称在某个class中呈嵌套装,那么它就是嵌套从属名称,如果它指涉的是某种类型,那么它就是嵌套从属类型名称,例如:
//这是一个用于接受STL容器作为参数的函数模板 template<tpyename T> void print2nd(const T&container){ if(container.size()>=2){ T::const_iterator iter=container.begin(); int value=*iter; std::cout<<value<<endl; } }
这个函数模板相当简单,它用于打印一个容器的第二个元素,其中value是int类型,它不依赖与类型参数,因此是非从属(non-independent)名称,而const_iterator就是嵌套从属类型名称.
实际上,这段代码无法通过编译,T::const_iterator存在歧义,它既可能是类T的嵌套类型名称,也有可能是T的static成员,面对这种歧义,C++在遇到嵌套从属名称时,它便假设这个名称不是一种类型,因此遇到T::const_iterator,解析器可能会将const_iterator解析为T的static数据成员,因此报错.
要解决这个问题,只需要在T::const_iterator之前加上typename关键字即可,即:
template<tpyename T> void print2nd(const T&container){ if(container.size()>=2){ typename T::const_iterator iter=container.begin(); int value=*iter; std::cout<<value<<endl; } }
注意,typename只能被用来指明嵌套从属类型名称,非嵌套从属类型名称不可使用用typename.此外,typename不可出现在base classes list内的嵌套从属类型名称之前,也不可在member initialization list中作为基类修饰符,例如:
template<typename T> class Derived:public Base<T>::Nested{//不可以用typename public: explict Derived(int x):Base<T>::Nested(x){//不可以用typename typename Base<T>::Nested temp;//可以用typename ... } ... private: ... }
3. 此外,不同编译器对typename相关规则的支持度可能不同,有些编译器接受的代码原本该有typename却遗漏了,原本不该有typename却出现了;还有少数编译器根本就拒绝typename.