模板参数中的typename的用法

首先在template的声明式中,class和typename有什么不同呢?答案是没有什么不同。
比如

template<class T> person
template<typename T> person

这两种声明方式我们在声明模板参数时,视其为等价的,不过老程序员可能更喜欢class,因为它在过去是主流用法,而且简短,少打几个字,可提高编程速度。但是本人比较喜欢typename,因为他指明了T是模板参数,不会与class类的含义混淆。

但是typename与class并不总是能互相取代的,在模板参数内部,有的时候需要用到typename来指明所用的类型是类型,我们把这用到typename来标明的类型称之为嵌套从属类型。

下面介绍嵌套从属类型:
举个例子

template<typename C>
void print2nd(const C& container)
{
    C::const_iterator* x;
}

看起来我们好像声明x为一个local变量,它是个指针,指向一个C::const_iterator。但它之所以被那么认为,只因为i我们“已经知道”C::const_iterator是个类型。但是编译器是无法探知C的作用域中变量的,因此编译器页不会知道const_iterator是一个类型。如果C::const_iterator真的不是个类型呢?如果C有个static成员变量碰巧被命名为const_iterator,同时如果x碰巧是个global变量名称呢?那样的话上述代码就不再是一声明一个local变量,而是一个相乘动作:C::const_iterator乘以x。当然,这听起来有点疯狂,但却并非没有可能,一个合格的程序员有责任考虑到这种输入。
因此此时应当用typename指明C::const_iterator是一种类型。

template<typename C>
void print2nd(const C& container)
{
    typename C::const_iterator* x;
}

这样就对了。再说一次,typename只用来修饰嵌套从属类型,比如C::const_iterator,而C也是一种类型,但它不是嵌套从属类型,所以它不必用typename修饰。

除此之外,typename在修饰嵌套从属类型时有两种例外情况
1.不允许出现在base class list内的嵌套从属类型名称之前
2.不允许出现在member initialization list内以它作为baseclass修饰符。
举个例子:

template<typename T>
class Derived:public Base<T>::Nested{//base class list 不允许
    public:
        explicit Derived(int x):Base<T>::Nested(x)//member initialization list 不允许
        {
            typename Base<T>::Nested temp;
        }
}

这样的不一致性确实挺令人头痛的,但是你敢学c++,就得做好接受这样不一致性的准备。(微笑脸)

猜你喜欢

转载自blog.csdn.net/qq_36946274/article/details/80795042