typename
的第一个作用在于声明一个类型。为什么类型还需要声明呢?因为编译器并不是总会知道哪个名称是个类型。 下面的代码会编译错:
template<typename C>void print2nd(const C& container){ if(container.size() >= 2){ C::const_iterator it(container.begin()); ++it; int value = *it; cout<<value; }}
发生编译错误是因为编译器不知道C::const_iterator
是个类型。万一它是个变量呢? C::const_iterator
的解析有着逻辑上的矛盾: 直到确定了C
是什么东西,编译器才会知道C::const_iterator
是不是一个类型; 然而当模板被解析时,C
还是不确定的。这时我们声明它为一个类型才能通过编译:
typename C::const_iterator it(container.begin());
事实上类型C::const_iterator
依赖于模板参数C
, 模板中依赖于模板参数的名称称为从属名称(dependent name), 当一个从属名称嵌套在一个类里面时,称为嵌套从属名称(nested dependent name)。 其实C::const_iterator
还是一个嵌套从属类型名称(nested dependent type name)。
嵌套从属名称是需要用typename
声明的,其他的名称是不可以用typename
声明的。比如下面是一个合法的声明:
template<typename C>void f(const C& container, typename C::iterator iter);
如果你把const C&
也声明了typename
也是要编译错的哦:
template<typename C>void f(typename const C& container, typename C::iterator iter);
错误输出:
error: expected a qualified name after 'typename'
模板中的嵌套从属名称是需要typename
声明的,然而有一个例外情况: 在派生子类的基类列表中,以及构造函数的基类初始化列表中,不允许typename
声明。 例如Derived<T>
继承自Base<T>::Nested
:
template<typename T>class Derived: public Base<T>::Nested{ // 继承基类列表中不允许声明`typename`public: explicit Derived(int x): Base<T>::Nested(x){ // 基类初始化列表不允许声明`typename` typename Base<T>::Nested tmp; // 这里是要声明的 }};
联系客服