C++ - 迭代器所需的运算符重载

C++ - Overloading of operators needed for an iterator

我正在尝试在允许读取特定文件格式的库上创建迭代器。

从文档中读取文件内容,您需要执行如下操作:

CKMCFile database;

if (!database.OpenForListing(path)) {
  std::cerr << "ERROR: unable to open " << path << std::endl;
}

CKMCFileInfo info;
database.Info(info);

CKmerAPI kmer(info.kmer_length);

uint32 cnt;
std::vector<uint64_t> data;
std::vector<uint64> ulong_kmer;
data.reserve(info.total_kmers);

while (database.ReadNextKmer(kmer, cnt)) {
  kmer.to_long(ulong_kmer);
  data.push_back(ulong_kmer[0]);
}

现在,我从这个开始 class wrapper:

class FileWrapper {
  CKMCFile database;
  CKMCFileInfo info;
  Iterator _end;

  public:
    explicit FileWrapper(const std::string &path) {
      if (!database.OpenForListing(path)) {
        std::cout << "ERROR: unable to open " << path << std::endl;
      }

      database.Info(info);
    }

    Iterator begin() {
      Iterator it;
      it.database = &database;
      it.total = 0;

      uint32_t cnt;
      std::vector<uint64_t> ulong_kmer;

      CKmerAPI tmp(info.kmer_length);
      database.ReadNextKmer(tmp, cnt);
      tmp.to_long(ulong_kmer);

      return it;
    }
    
    Iterator end() const { return _end; }
    uint64_t size() { return info.total_kmers; }
};

然后,这是 Iterator class:

class Iterator {
    friend class FileWrapper;

    CKMCFileInfo info;
    CKMCFile *database;
    uint64_t kmer, total;
    
    public:
      Iterator &operator++() {
        ++total;

        uint32_t cnt;
        std::vector<uint64_t> ulong_kmer;

        CKmerAPI tmp(info.kmer_length);
        database->ReadNextKmer(tmp, cnt);
        tmp.to_long(ulong_kmer);

        return *this;
      }

      bool operator<(const Iterator &rhs) const { return total < rhs.total; }
      uint64_t operator*() const { return kmer; }
  };

但是,在某些测试中,我无法将 for loop 用于 for (auto it = begin(); it != end(); ++i) { ... }begin() + size() 之类的东西。我怎样才能正确重载这两个操作符? opeartor!=operato+

你必须先考虑两件大事:

  1. 所有权。目前,您必须确保您的 FileWrapper 至少与通过调用它的 begin() 从它返回的任何 Iterator 一样长(因为您的 Iterator 存储指向拥有的数据的指针通过 FileWrapper 对象)。如果你不能保证,也许考虑使用 unique_ptrs 或 shared_ptrs
  2. 迭代器类别。正如评论中所讨论的,您的数据库似乎要求您使用“input iterators”。它们只能递增 1(不提供 operator+(int))并取消引用。实际上,迭代器 begin() + 10 会是什么样子?如果这应该使您的文件指针前进,那么您 不能 将结尾定义为 begin() + size(),因为那样只会跳过文件。
  3. 代表。结束迭代器应该是什么样的?一个简单的选择可能是用 database == nullptr 表示结束。在这种情况下,operator!= 可能如下所示:
bool is_end() const { return database == nullptr; }

bool operator==(const Iterator& other) const {
  if(is_end()) return other.is_end();
  if(other.is_end()) return false;
  return (database == other.database) && (total == other.total);
}

bool operator!=(const Iterator& other) const { return !operator==(other); }

现在,您需要确保所有结束迭代器都具有 database == nullptr 的代码,并且每当非结束迭代器通过应用 operator++() 变为结束迭代器时,您将需要设置 database = nullptrtotal = 0(或其他)。

末尾的注释:您的 Iterator 可能在构造之后和分配其 database 成员之前处于不一致状态。明智的做法是为 Iterator 声明一个适当的构造函数来初始化其成员。

编辑:here 的集成建议