例子
template<typename T>
void func(){
vector<int>::iterator it_int;
vector<T>::iterator it;
}
编译后提示:[Error] need ‘typename’ before ‘std::vector::iterator’ because ‘std::vector’ is a dependent scope
上面的用法想必应该很常见吧, 这样写在VC下编译通过, 然而在gcc下编译是会出现如上错误的. 在google上大概搜了下, stackoverflow倒是有解析, 但中文的解析就比较零散, 所以在这里写一些个人的理解, 希望能帮到一些像我一样英文不太好的同学, 顺便也帮助一下自己理解模板的概念…
概念
要想搞清楚这个问题首先需要区分两个概念
(以下概念均为个人浅显的理解, 如有错误敬请指正)
模板 : 模板不是函数或类, 正如字面理解, 它并不是一个可以拿来使用的实在的对象, 也就是没有实体, 用来根据你所给它的类型参数帮你生成一个可以拿来使用的实例对象.
模板实例化 : 给模板以类型参数之后, 模板创建实例对象的过程.
模板特化 : 针对某些特定的具体类型, 对模板进行修改使其对于该类型的实例对象的行为不同.
分析
首先注意到, vector<int>::iterator it_int;
是可以通过的, 而用模板参数类型T声明的vector<T>::iterator it;
却不能通过, 它们的关键区别在于vector<int>
是实例化之后的一个实在的类型, 而vector<T>
还是一个模板类型, 如何实例化还需要取决于外部实际传进来的类型参数T.
正如编译器的错误提示because ‘std::vector’ is a dependent scope, dependent scope就指出了这个类型还需要依赖别的条件, 也就是传进来的类型参数, 与上面的分析是一致的.
原因
但是为什么编译器不能直接根据模板类型的定义来实现这个声明呢?
原因在于编译器无法识别std::vector<T>::iterator
这个名称是一个成员变量还是一个类型. 因为假如vector这个类被特化了, 如在vector类定义的文件内有下列代码:
template <>
class vector<char>{
int iterator;
// ..detail omitted
}
那么std::vector<char>::iterator
这个名称就是一个成员变量了, 把它当做类型就不能在适用了.
因此, 为了防止出现这样的歧义, 正如编译器提示的, 需要在std::vector<char>::iterator
之前加一个关键字typename
来显式地说明它是一个类型而, 非成员变量.
参考
“Where and why do I have to put the “template” and “typename” keywords”