如何改进自引用模板实现?

时间:2015-03-31 18:47:33

标签: c++ templates

如何在给定的自引用模板实现中摆脱抽象类?

我只是尝试实现跳过列表数据结构。 所以我想创建模板Node,以便我可以为不同的节点类实例化下一个链接的类,以避免类转换。 找到了这些问题:

Self-referencing Template in Template Argument

How to properly declare a self-referencing template type?

但他们都没有解决方案。然后我根据两行继承制作了自己的解决方案。一个是“抽象”模板的序列(用于Next参数传播)。另一种是实例化具体类。但感觉可以改进处理相同而没有冗余的抽象模板(NodeAbstract,NodeWithKeyAbstract等)。经过几次尝试后,我想请你帮助我:

template <class Value, class Next >
class NodeAbstract
{
public:
    Value m_value;

    Next * next;

    NodeAbstract () : next(0) {}
    Next * getNext() {return next;}
};

template <class Value, class Key, class Next >
class NodeWithKeyAbstract : public NodeAbstract <Value, Next >
{
public:
    Key m_key;
};

template <class Value, class Key>
class NodeWithKey : public NodeWithKeyAbstract <Value, Key, NodeWithKey<Value,Key> >
{
};

template <class Value, class Key, int maxlevel, class Next>
class NodeSkipListAbstract : public NodeWithKeyAbstract<Value, Key, Next >
{
public:
    Next * nextjump[maxlevel-1];
};

template <class Value, class Key, int maxlevel>
class NodeSkipList : public NodeSkipListAbstract<Value, Key, maxlevel, NodeSkipList<Value, Key, maxlevel> >
{
};

1 个答案:

答案 0 :(得分:1)

如果我理解正确,你的问题基本上是不同的maxlevel值会产生不同的类,所以你不能使用一个数组来存储它们(如果我和#39;我错了。)

你不能完全摆脱抽象类 - 如果你想让不同最高级别的节点作为不同的类(不同的模板特化),你必须为它们提供一些共同点。

好消息是你可以摆脱奇怪的重复模板模式 - 因为你使用指针你不必参考确切的实现类型(例如,知道确切的模板专业化)如果你的抽象给出了您可以访问所需的所有信息。您的代码也可以简化一点。

考虑以下代码:

template <class Key, class Value>
class Node {
 public:
  virtual ~Node() = default;

  virtual std::size_t MaxLevel() const = 0;
  virtual Node* Skip(size_t level) const = 0;
  // add setter as well

  Key key;
  Value value;
};

template <class Key, class Value, std::size_t max_level>
class NodeImpl : public Node<Key, Value> {
 public:
  typedef Node<Key, Value> node_type;

  NodeImpl() : skips() {}

  size_t MaxLevel() const { return max_level; }
  node_type* Skip(std::size_t level) const {
    return level < max_level ? skips[level] : nullptr;
  }
  // add setter as well

 private:
  node_type* skips[max_level];
};

template <class Key, class Value>
class SkipList {
  public:
   typedef Node<Key, Value> node_type;

   node_type* head;
};

这里Node为你提供了跳过&#34;跳过&#34;行为。 NodeImpl将用于生成具有不同最高级别的Node,但最终使用的实现对您来说是透明的 - 您只能使用Node的界面。同样在语法级别上,您只使用Node*类型,因此各种实现都不会成为问题。虚析构函数将确保delete释放所有内存,keyvalue始终可以作为公共字段访问。

这个代码当然可以改进。原始数组可以由std::array替换。如果您决定使用max_level并在构造函数中设置大小而不是数组(那么您只有std::vector和{Node,那么SkipList作为模板的整体想法可以摆脱{1}})。作为奖励创建新节点会更容易,因为现在您必须编写一些工厂,其中所有NodeImpl的特化都是从1到某个值。另外,指针可以被一些智能指针替换,以避免内存泄漏。