3

我想设计一个类Foo来存储不同类型的各种数据并返回迭代器。它应该是通用的,因此用户Foo不知道数据是如何存储的(Foo可能正在使用std::setstd::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任何机会吗?)

4

5 回答 5

4

你明白为什么 STL 选择将迭代器实现细节放在头文件中了吗?JIT 框架能够跨编译单元内联,但 C++ 只能在编译单元内内联。内联时通过序列推进要快得多,函数调用的成本实际上是遍历数据结构的主要因素。

如果您真的想隐藏实现细节,请继续。您可以创建一个兼容 STL 的迭代器,根据受保护的虚函数实现 operator++ 和 operator!= 和 operator->,您提到的 Next、Done 和 Value 将是不错的名称。只是期望以较低的性能为封装付费。

于 2010-02-20T21:27:29.480 回答
1

使用 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++) { // ... }

这不是通用的,但同样的想法可以用于模板。

于 2010-02-20T20:32:10.100 回答
1

如果必须使用 std 库,具有迭代器的 c++ 类必须提供至少两个函数

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 是您的容器的类型。(该类不完整,我可能混淆了一些东西)

于 2010-02-20T20:39:55.200 回答
1

几乎看起来您正在尝试创建独立于容器的代码,这(通常)不是一个好主意,除非您正在编写一个可以单独使用迭代器操作的算法。(参见 Scott Myers Effective STL Item 2:当心容器独立代码的错觉)

问题是大多数标准容器不提供重叠功能。如果您正在为特定容器编写代码,则假设您正在为该容器编写代码。不要费心让它独立于容器。

于 2010-02-21T03:08:18.490 回答
-1

为了满足头文件中没有提到特定容器(向量,集合,...)的要求,并且用户将能够遍历所有字符串,就是使用访问者模式。当然,缺点是用户不能在字符串上使用 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;
}
于 2010-02-20T21:33:07.870 回答