CLion中对函数进行定义的问题

来源:5-8 二分搜索树节点的删除(Hubbard Deletion)

mahsiaoko

2020-03-07

我在类中声明如下:

Node *insert(Node *node, Key key, Value value);

在类外面进行定义时,为什么需要使用如下方式:

template<typename Key, typename Value>
typename BST<Key, Value>::Node *BST<Key, Value>::insert(BST::Node *node, Key key, Value value)

为什么在BST<Key,Value>之前加一个typename?而且insert的参数里面,Node前面只需要是BST,不用写成BST<Key,Value>

写回答

1回答

liuyubobobo

2020-03-08

简单的来说,在 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)


继续加油!:)

0
1
mahsiaoko
非常感谢!
2020-03-08
共1条回复

算法与数据结构(C++版) 面试/评级的算法复习技能包

课程专为:短时间内应对面试、升职测评等艰巨任务打造

11187 学习 · 1614 问题

查看课程