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;
    }
}
View Code

这个函数模板相当简单,它用于打印一个容器的第二个元素,其中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;
    }
}
View Code

注意,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:
    ...
}
View Code

3. 此外,不同编译器对typename相关规则的支持度可能不同,有些编译器接受的代码原本该有typename却遗漏了,原本不该有typename却出现了;还有少数编译器根本就拒绝typename.

posted @ 2015-09-11 11:19  Reasno  阅读(412)  评论(0编辑  收藏  举报