测试对象在容器中的成员资格

由于节点存储是容器中现有对象的属性,因此可以检查对象本身,以确定对象当前是否包含在容器中。这项检查始终是一项快速的 O(1) 操作。

本指南的这一部分将介绍测试对象当前是否是其当前可能包含的任何容器的成员的各种方法。

使用 mix-ins 测试单容器对象

所有节点状态类都提供一个公共 InContainer() 方法,该方法可用于测试节点状态实例当前是否是其容器的成员,对象通常衍生自 ListableContainable 混合对象也是如此。由于这些对象派生自混合加入,因此它们也会公开此方法,因此,如果测试使用混入且只能是单个容器的成员,则测试容器成员资格非常简单,只需对对象调用 InContainer() 即可。

class Obj : public fbl::SinglyLinkedLisable<Obj*> { /* ... */ };

Obj* the_obj = new Obj();
fbl::SinglyLinkedList<Obj*> the_list;
ASSERT(the_obj->InContainer() == false);

the_list.push_front(the_obj);
ASSERT(the_obj->InContainer() == true);

the_list.clear();
ASSERT(the_obj->InContainer() == false);

delete the_obj;

使用混合的多容器对象,不使用 ContainableBaseClasses

当一个对象由于派生自多次混合而可以成为多个容器的成员时,情况可能会变得有点复杂。该对象本身现在具有多个 InContainer() 实现,这些实现是从混音中继承的,因此调用方需要明确他们想要调用哪个实现。虽然这当然可以,但语法尴尬,如果将其封装在对象的自定义方法中,可能会带来很多好处。例如:

class Obj : public fbl::DoublyLinkedListable<Obj*>,
            public fbl::WAVLTreeContainable<Obj*> {
 public:
   // ...
   bool InList() const { return this->DoublyLinkedListable<Obj*>::InContainer(); }
   bool InTree() const { return this->WAVLTreeContainable<Obj*>::InContainer(); }
   // ...
};

void test(const Obj& obj) {
  bool in_list, in_tree;

  // The hard way
  in_list = obj.DoublyLinkedListable<Obj*>::InContainer();
  in_tree = obj.WAVLTreeContainable<Obj*>::InContainer();

  // The slightly easier way (the class still needs to implement the hard way)
  in_list = obj.InList();
  in_tree = obj.InTree();
}

使用 Mix-in 和 ContainableBaseClasses 的多个容器对象

同时针对多个容器中的现有容器使用 ContainableBaseClasses 可以大大简化这一过程,因为这让您可以使用代码来选择要测试成员资格的容器。fbl:: 提供了一个独立的 InContainer 函数,该函数可以与标记一起使用,以便更轻松地测试成员资格。我们来看一下上一个示例,但这次使用的是 ContainableBaseClasses

struct ListTag {};
struct TreeTag {};

class Obj
  : public fbl::ContainableBaseClasses<fbl::TaggedDoublyLinkedListable<Obj*, ListTag>,
                                       fbl::TaggedWAVLTreeContainable<Obj*, TreeTag>> { /* ... */ };

void test(const Obj& obj) {
  bool in_list = fbl::InContainer<ListTag>(obj);
  bool in_tree = fbl::InContainer<TreeTag>(obj);
}

直接使用 NodeState 对象进行测试

最后,如果使用的是 NodeState 对象和自定义特征,您仍然可以测试容器成员资格,但您需要直接请求 NodeState 实例。

class Obj {
 public:
  // Obj impl here

  bool InFooList() const { return foo_list_node_.InContainer(); }
  bool InBarList() const { return bar_list_node_.InContainer(); }

 private:
  struct FooListTraits {
    static auto& node_state(Obj& obj) {
      return obj.foo_list_node_;
    }
  };

  struct BarListTraits {
    static auto& node_state(Obj& obj) {
      return obj.bar_list_node_;
    }
  };

  friend struct FooListTraits;
  friend struct BarListTraits;

  fbl::DoublyLinkedListNodeState<Obj*> foo_list_node_;
  fbl::DoublyLinkedListNodeState<fbl::RefPtr<Obj>> bar_list_node_;

 public:
  using FooList = fbl::DoublyLinkedListCustomTraits<Obj*, FooListTraits>;
  using BarList = fbl::DoublyLinkedListCustomTraits<fbl::RefPtr<Obj>, BarListTraits>;
};