如何从unique_ptr <base />的向量中获取派生迭代器?

时间:2014-03-27 19:00:43

标签: c++ c++11 vector iterator unique-ptr

我有一个基类(Container),它在Base的向量中包含各种对象(std::unique_ptr<Base>项),并且我有一个派生类(FolderOfFolders )只保存特定项目(Folder项目)。我想使用基于范围的for来遍历该特定对象(FolderOfFolder),但我不知道该怎么做。使用基于范围的 - 我可以返回std::unique_ptr<Base>项,但我想要const Folder*项。我知道我需要一个begin(),end()对来为基于范围的for提供迭代器,但我需要从std::unique_ptr<Base>const Folder*的转换。这有可能吗?

class Container : public Base {
  public:
    // I want to get back these as Folder* from FolderOfFolders
    std::vector<std::unique_ptr<Base>> items;
};

class Folder : public Container {
  public:
   // I want to call this when I traverse FolderOfFolders with range-based-for
   void folderMethod();
   ...
};

class SystemFolder : public Folder {
  public:
   ...
};

class UserFolder : public Folder {
  public:
   ...
};

class FolderOfFolders : public Folder {
  public:

    // I know that every item is a Folder in items
    // can I get an iterator to a Folder* ?!
    iterator begin() {
      //  ???
      return items.begin();
    }
    iterator end() {
       // ???
       return items.end();
    }
};

我想用它作为

FolderOfFolders folderOfFolders;
for (folder : folderOfFolders)
  folder->folderMethod();

2 个答案:

答案 0 :(得分:3)

#include <boost/iterator/transform_iterator.hpp>

struct Downcast
{
  typedef const Folder* result_type;

  result_type operator()(const std::unique_ptr<Base>& p) const
  { return static_cast<const Folder*>(p.get()); }
};

class FolderOfFolders : public Folder {
  public:

    typedef boost::transform_iterator<Downcast, decltype(items)::iterator> iterator;

    iterator begin() {
      return iterator(items.begin(), Downcast());
    }
    iterator end() {
      return iterator(items.end(), Downcast());
    }
};

N.B。因为FolderOfFolders::iterator::operator*按值返回const Folder*,这意味着FolderOfFolders::iterator::reference不是引用类型,因此迭代器只是一个InputIterator,而不是像底层vector::iterator那样的RandomAccessIterator,但这足以与基于范围的for一起使用。

然而,这个“一切都是Base,所有集合都是Base的集合”,闻起来像Java。有更好的设计。即使你必须存储Base的容器,你也可以这样做,而不必改变迭代器类型:

const Folder& asFolder(const Base& b) {
  return dynamic_cast<const Folder&>(b); 
}

class FolderOfFolders : public Folder {
  public:

    typedef decltype(items)::iterator iterator;

    iterator begin() {
      return items.begin();
    }
    iterator end() {
      return items.end();
    }
};

...

for (auto& base_ptr : folderOfFolders)
  asFolder(*base_ptr).folderMethod();

答案 1 :(得分:0)

您的解决方案是参考:

for (auto &folder : folderOfFolders)
    folder->folderMehod();

std::unique_ptr<>个对象不是可复制的,但您可以使用引用绑定迭代。