拥有 X 类,如何将 X 作为模板参数传递给自身?
Posted
技术标签:
【中文标题】拥有 X 类,如何将 X 作为模板参数传递给自身?【英文标题】:Having class X, how to pass X as a template argument to itself? 【发布时间】:2020-10-01 09:28:33 【问题描述】:我正在尝试实现从 BS 树继承的红黑树。 BST
使用BSNode
作为其节点,而RBT
(红黑树)使用RBNode
,而RBNode
又继承自BSNode
。代码长这样,问题出在代码中:
#include <iostream>
#define _BST BST<K, T, RBNode<K, T>>
// attempt 1
//template <typename K, typename T, typename NODE>
//class BSNode
//
//
//public:
//
// K key;
// T value;
//
// NODE* left;
// NODE* right;
//
// // ...
//;
// attempt 2
template <typename K, typename T, template<typename, typename> typename NODE>
class BSNode
public:
K key;
T value;
NODE<K, T>* left;
NODE<K, T>* right;
// ...
;
template <typename K, typename T>
class RBNode : public BSNode<K, T, RBNode>
public:
bool color;
// ...
;
template <typename K, typename T, typename NODE>
class BST
public:
NODE* root = nullptr;
// ...
;
template <typename K, typename T>
class RBT : public _BST
// ...
;
int main()
RBT<int, int> rbt;
// attempt 1
// recursive and can't be done.
// BST<int, int, BSNode<int, int, BSNode<int, int, BSNode<int.....
// attempt 2
// template arguments list for NODE takes
// 2 arguments while BSNode takes 3. Not compatible.
// BST<int, int, BSNode<int, int, BSNode>>
问题:
1 -
如何实现它以便BST
s 只写为BST<int, int>
,同时仍然让它接受不同类型的左右节点,例如RBNode
?
2 -
如何让RBNode
从BSNode
继承,同时能够创建BST和RBT
s?
3 -
在尝试 2 中,在宏 #define _BST BST<K, T, RBNode<K, T>>
中,为什么将其写为 #define _BST BST<K, T, RBNode>
时会出错?在BSNode
类中,定义了left和right
作为NODE<K, T>*
。这意味着将 NODE
替换为 BSNode<K, T>
将导致 left 和
正确等于BSNode<K, T><K, T>*
。为什么这是正确的方式?
设计是否有问题或是否可以改进?
【问题讨论】:
恐怕你错过了一个额外的间接级别。我认为惯用的方法是使用 CRTP。 @πάνταῥεῖ 你能举个例子吗? 当然:***.com/questions/4173254/…RBNode
应该作为派生自BST
的类类型传递。
标题的问题在于X
要么是类,要么是类模板。无关:_BST
是为实现保留的名称。
【参考方案1】:
您需要将Node
和Tree
与特定的BSNode
、RBNode
、BSTree
和RBTree
类型分开
template <typename K, typename T, template<typename, typename> typename NODE>
struct Node
K key;
T value;
NODE<K, T>* left;
NODE<K, T>* right;
// ...
;
template <typename K, typename T>
struct BSNode : Node<K, T, BSNode>
;
template <typename K, typename T>
struct RBNode : Node<K, T, RBNode>
bool color;
// ...
;
template <typename NODE>
struct Tree
NODE* root = nullptr;
// ...
;
template <typename K, typename T>
struct BSTree : Tree<BSNode<K, T>>
// ...
;
template <typename K, typename T>
struct RBTree : Tree<RBNode<K, T>>
// ...
;
除此之外:如果您正在制作 public
的所有内容,那么您最好使用 struct
而不是 class
。唯一的区别是默认public
。
【讨论】:
嗯,我想过这种方式,但我不确定这是否是一个好的解决方案。现在,BSNode 不再是 RBNode 的父级,而是兄弟姐妹,RBNode 可以' 不能代替 BSNode。另外,如果您能够为问题 3 提供答案,我将不胜感激。谢谢! @StackExchange123 它们不是同一类型,所以最好不要混合它们。 #3 是因为您将NODE
定义为类型,而不是模板。在BST
中没有你写NODE<K, T>
感谢您的回复。我相信 RBNode 只是一个添加了布尔颜色的 BSNode。为什么你说它们不是同一类型?
因为你不应该把RBNode
放在BSTree
中
您仍然可以编写不关心是否传递 BSTree
或 RBTree
而没有继承的函数【参考方案2】:
问题在于节点定义。为简单起见,最好使用节点作为树本身,因此删除 BST 和 RBT 类。
节点类可以定义为:
template <typename K, typename T, template<typename, typename> typename Node>
class GenericNode
public:
K key;
T value;
Node<K, T>* left = nullptr;
Node<K, T>* right = nullptr;
// common code
;
template <typename K, typename T>
class BSNode : public GenericNode<K, T, BSNode>
// specific code if exists
;
template <typename K, typename T>
class RBNode : public GenericNode<K, T, RBNode>
public:
bool color;
// specific code
;
int main()
BSNode<int, float> n1, n2, n3;
n1.left = &n2;
n1.right = &n3;
RBNode<int, float> n1, n2, n3;
n1.left = &n2;
n1.right = &n3;
n1.color = true;
回复 3. NODE
【讨论】:
感谢您的回答,但这并不能回答问题 3,另外,树和节点是不同的东西。例如,树将包含根节点,而节点则不包含。 我添加了回复 3. 树节点和树的主要区别是什么? “std::unique_ptr以上是关于拥有 X 类,如何将 X 作为模板参数传递给自身?的主要内容,如果未能解决你的问题,请参考以下文章