简单的来说,在 C++ 中,如果牵扯到模板类下的一个从属类型,比如 Node 就是 BST<Key,Value> 这个模板类下的从属类型,此时,就需要使用 typename,来告诉编译器,Node 是一个类型(是一个 type),而不是一个变量,这就是 typename 的意思。
原因就是 C++ 编译器很笨,在解析的时候,分不清楚 Node 是一个类型,需要我们显式地告诉它。
同理,insert 参数中的 Node* node 这个参数的定义,也可以这么写。完整的写出来是这样:
template<typename Key, typename Value>
typename BST<Key, Value>::Node* BST<Key, Value>::insert(typename BST<Key, Value>::Node *node, Key key, Value value)
但是,在处理 insert 参数的时候,C++ 的编译器又变得很聪明。
首先,因为 C++ 编译器解析到这里,已经明确 insert 是一个函数,括号里是参数列表,所以 Node 肯定是一个 type 了,所以可以省略 typename;
其次,对于 BST,因为之前的声明已经明确了 insert 是模板类 BST<Key, Value> 中的函数,这里模板类型已经表达的很清楚了,所以,可以直接写 BST。
这个语言特性叫做类型推断,很多语言都有,虽然引发推断的位置不一定一样。Java 在 7 或者 8 的时候也引入了类型推断。至于无类型或者弱类型语言,到处都是类型推断。我不确定 C++ 是哪个版本引入的,但 C++ 11 肯定支持。
不过,如果对这些语法觉得容易混淆,我觉得就把他们写全就好了,这样写没有歧义:
template<typename Key, typename Value>
typename BST<Key, Value>::Node* BST<Key, Value>::insert(
typename BST<Key, Value>::Node *node,
Key key,
Value value)
继续加油!:)