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+
你必须先考虑两件大事:
- 所有权。目前,您必须确保您的
FileWrapper
至少与通过调用它的 begin()
从它返回的任何 Iterator
一样长(因为您的 Iterator
存储指向拥有的数据的指针通过 FileWrapper
对象)。如果你不能保证,也许考虑使用 unique_ptr
s 或 shared_ptr
s
- 迭代器类别。正如评论中所讨论的,您的数据库似乎要求您使用“input iterators”。它们只能递增 1(不提供
operator+(int)
)并取消引用。实际上,迭代器 begin() + 10
会是什么样子?如果这应该使您的文件指针前进,那么您 不能 将结尾定义为 begin() + size()
,因为那样只会跳过文件。
- 代表。结束迭代器应该是什么样的?一个简单的选择可能是用
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 = nullptr
和 total = 0
(或其他)。
末尾的注释:您的 Iterator
可能在构造之后和分配其 database
成员之前处于不一致状态。明智的做法是为 Iterator
声明一个适当的构造函数来初始化其成员。
编辑:here 的集成建议
我正在尝试在允许读取特定文件格式的库上创建迭代器。
从文档中读取文件内容,您需要执行如下操作:
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+
你必须先考虑两件大事:
- 所有权。目前,您必须确保您的
FileWrapper
至少与通过调用它的begin()
从它返回的任何Iterator
一样长(因为您的Iterator
存储指向拥有的数据的指针通过FileWrapper
对象)。如果你不能保证,也许考虑使用unique_ptr
s 或shared_ptr
s - 迭代器类别。正如评论中所讨论的,您的数据库似乎要求您使用“input iterators”。它们只能递增 1(不提供
operator+(int)
)并取消引用。实际上,迭代器begin() + 10
会是什么样子?如果这应该使您的文件指针前进,那么您 不能 将结尾定义为begin() + size()
,因为那样只会跳过文件。 - 代表。结束迭代器应该是什么样的?一个简单的选择可能是用
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 = nullptr
和 total = 0
(或其他)。
末尾的注释:您的 Iterator
可能在构造之后和分配其 database
成员之前处于不一致状态。明智的做法是为 Iterator
声明一个适当的构造函数来初始化其成员。
编辑:here 的集成建议