[英]How to return a generic iterator (independent of particular container)?
我想設計一個類Foo
,它存儲不同類型的各種數據,並通過它們返回迭代器。 它應該是通用的,因此Foo
的用戶不知道數據是如何存儲的( Foo
可能使用std::set
或std::vector
或其他)。
我很想寫一個這樣的界面:
class Foo {
class FooImpl;
FooImpl* impl_;
public:
const Iterator<std::string>& GetStrings() const;
const Iterator<int>& GetInts() const;
};
Iterator
就像這樣(就像.NET中的迭代器一樣):
template<class T>
class Iterator {
public:
const T& Value() const = 0;
bool Done() const = 0;
void Next() = 0;
};
但是我知道這種迭代器在C ++中不是標准的,並且最好像STL一樣使用迭代器,所以你可以在它們上使用STL算法。
我怎樣才能做到這一點? (我有機會需要iterator_traits
嗎?)
您是否理解為什么STL選擇將迭代器實現細節放在頭文件中? JIT框架能夠跨編譯單元內聯,但C ++只能在編譯單元中內聯。 內聯時推進序列的速度要快得多,函數調用的成本實際上主要是遍歷數據結構。
如果您真的想隱藏實現細節,請繼續。 你可以創建一個STL兼容的迭代器來實現operator ++和operator!=和operator->就受保護的虛函數而言,你提到的Next,Done和Value都是不錯的名字。 只希望以較低的性能為封裝付費。
使用typedef返回boost::iterator_range
。 例如(不要介意名字),
class Container
{
typedef std::vector<int> Collection;
public:
typedef boost::iterator_range<Collection::iterator> CollectionRange;
typedef Collection::iterator CollectionIterator;
Range range() const {
return make_iterator_range(collection_.begin(), collection_.end());
}
private:
Collection collection_;
};
用戶代碼將是
Container c;
// ...
FOREACH(int i, c.range()) { //... }
Container::Range r = c.range();
for(Container::iterator j = r.begin(); j!= r.end(); j++) { // ... }
這不是通用的,但同樣的想法可以用於模板。
帶有迭代器的c ++類必須至少提供兩個函數,如果它們必須使用std庫
iterator begin() //returns an iterator at starting pos
iterator end() //returns an iterator one past end or just invald
迭代器必須重載增量運算符,等於和*
iterator operator++()
iterator operator==()//make sure that an invalid iterator equals end()
T& operator*()
您可以使用迭代器類來包裝內部存儲的迭代器,以確保用戶僅限於這些方法。
template <typename T> iter
{
iter(T::iterator& intern)
T::value_type& operator*(){return *intern}
iter operator++(){return iter(++intern);}
bool operator==(iter const& other)const{return intern == other.intern;}
}
其中T是你的容器的類型。(這個類是不完整的,我可能混淆了一些東西)
它幾乎看起來像你正在嘗試創建與容器無關的代碼,這通常不是一個好主意,除非你正在編寫一個只能用迭代器操作的算法。 (參見Scott Myers Effective STL第2項:注意與容器無關的代碼的錯覺)
問題是大多數標准容器不提供重疊功能。 如果您正在為特定容器編寫代碼,請假設您正在為該容器編寫代碼。 不要試圖使其與容器無關。
為了滿足頭文件中未提及特定容器(vector,set,...)以及用戶將能夠遍歷所有字符串的要求,使用訪問者模式 。 當然,缺點是用戶將無法在字符串上使用STL算法。
// foo.h
class StringVisitor {
public:
void accept(const std::string& str) {
std::cout << str << std::endl;
}
};
class Foo {
class Impl;
Impl* impl_;
public:
Foo();
~Foo();
void VisitStrings(StringVisitor v) const;
};
// foo.cc
class Foo::Impl {
typedef std::vector<std::string> StringContainer;
StringContainer str_;
public:
Impl() {
str_.push_back("a");
str_.push_back("b");
}
void VisitStrings(StringVisitor v) const {
for(StringContainer::const_iterator it = str_.begin();
it != str_.end(); ++it){
v.accept(*it);
}
}
};
Foo::Foo() : impl_(new Impl()) {}
Foo::~Foo() {delete impl_;}
void Foo::VisitStrings(StringVisitor v) const {
impl_->VisitStrings(v);
}
// main.cc
int main() {
Foo foo;
foo.VisitStrings(StringVisitor());
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.