一个C++迭代器适配器,它包装和隐藏内部迭代器并转换迭代类型

El *_*rko 15 c++ templates iterator adapter wrapper

玩弄了这个,我怀疑它不可能,但我想我会问专家.我有以下C++代码:

class IInterface
{
    virtual void SomeMethod() = 0;
};

class Object
{
    IInterface* GetInterface() { ... }
};

class Container
{
private:
    struct Item
    {
        Object* pObject;
        [... other members ...]
    };
    std::list<Item> m_items;
};

我想将这些方法添加到Container:

    MagicIterator<IInterface*> Begin();
    MagicIterator<IInterface*> End();

为了让呼叫者可以写:

Container c = [...]
for (MagicIterator<IInterface*> i = c.Begin(); i != c.End(); i++)
{
    IInterface* pItf = *i;
    [...]
}

所以基本上我想提供一个类似乎迭代某些集合(其中Begin()和End()的调用者不允许看到)的IInterface指针,但它实际上迭代了指向其他指针的指针集合.对象(Container类专用),可以转换为IInterface指针.

几个关键点:

  • MagicIterator是在外面定义的Container.
  • Container::Item 必须保持私密.
  • MagicIterator有遍历IInterface,指针尽管事实Container持有std::list<Container::Item>.Container::Item包含一个Object*,Object可用于获取IInterface*.
  • MagicIterator必须可以重用几个类似于Container的类,但可能在内部有不同的列表实现std::vector<SomeOtherItem>,每个时间以不同的方式保存不同的对象(,mylist<YetAnotherItem>)IInterface*.
  • MagicIterator不应该包含特定于容器的代码,尽管它可以委托给那样做的类,只要这样的委托不是硬编码到内部的特定容器MagicIterator(例如,由编译器以某种方式自动解析).
  • 解决方案必须在Visual C++下编译而不使用其他库(例如boost),这需要其作者的许可协议.
  • 此外,迭代可能不会分配任何堆内存(所以没有new()malloc()在任何阶段),没有memcpy().

感谢您的时间,即使您只是在阅读; 这个人真的在烦我!

更新:虽然我有一些非常有趣的答案,但还没有一个满足上述所有要求.值得注意的是,棘手的领域是:i)以某种方式将MagicIterator与Container分离(默认模板参数不会削减它),以及ii)避免堆分配; 但我真的想要一个涵盖所有上述子弹的解决方案.

jpa*_*cek 15

我认为你有两个不同的问题:

首先,创建一个迭代器,它将返回IInterface*你的list<Container::Item>.这很容易完成boost::iterator_adaptor:

class cont_iter
  : public boost::iterator_adaptor<
        cont_iter                       // Derived
      , std::list<Container::Item>::iterator // Base
      , IInterface*                     // Value
      , boost::forward_traversal_tag    // CategoryOrTraversal
      , IInterface*                     // Reference :)
    >
{
 public:
    cont_iter()
      : cont_iter::iterator_adaptor_() {}

    explicit cont_iter(const cont_iter::iterator_adaptor_::base_type& p)
      : cont_iter::iterator_adaptor_(p) {}

 private:
    friend class boost::iterator_core_access;
    IInterface* dereference() { return this->base()->pObject->GetInterface(); }
};
Run Code Online (Sandbox Code Playgroud)

您可以创建这种类型的内部Container,并从其返回begin()end()方法.

其次,您需要运行时多态MagicIterator.这正是这样any_iterator做的.的MagicIterator<IInterface*>只是any_iterator<IInterface*, boost::forward_traversal_tag, IInterface*>,并且cont_iter可以只分配给它.


str*_*ger 5

创建一个抽象IteratorImplementation类:

template<typename T>
class IteratorImplementation
{
    public:
        virtual ~IteratorImplementation() = 0;

        virtual T &operator*() = 0;
        virtual const T &operator*() const = 0;

        virtual Iterator<T> &operator++() = 0;
        virtual Iterator<T> &operator--() = 0;
};
Run Code Online (Sandbox Code Playgroud)

以及一个Iterator围绕它的类:

template<typename T>
class Iterator
{
    public:
        Iterator(IteratorImplementation<T> * = 0);
        ~Iterator();

        T &operator*();
        const T &operator*() const;

        Iterator<T> &operator++();
        Iterator<T> &operator--();

    private:
        IteratorImplementation<T> *i;
}

Iterator::Iterator(IteratorImplementation<T> *impl) :
    i(impl)
{
}

Iterator::~Iterator()
{
    delete i;
}

T &Iterator::operator*()
{
    if(!impl)
    {
        // Throw exception if you please.
        return;
    }

    return (*impl)();
}

// etc.
Run Code Online (Sandbox Code Playgroud)

(您可以在IteratorImplementation“内部”创建一个类Iterator以保持整洁。)

在您的类中Container,返回一个Iterator带有自定义子类的实例:IteratorImplementationctor

class ObjectContainer
{
    public:
        void insert(Object *o);
        // ...

        Iterator<Object *> begin();
        Iterator<Object *> end();

    private:
        class CustomIteratorImplementation :
            public IteratorImplementation<Object *>
        {
            public:
                // Re-implement stuff here.
        }
};

Iterator<Object *> ObjectContainer::begin()
{
    CustomIteratorImplementation *impl = new CustomIteratorImplementation();  // Wish we had C++0x's "var" here.  ;P

    return Iterator<Object *>(impl);
}
Run Code Online (Sandbox Code Playgroud)


El *_*rko 0

我现在找到了一个更适合我最初目的的解决方案。但我还是不喜欢它:)

该解决方案涉及在 IInterface* 上模板化 MagicIterator,并使用迭代器的 void*、所述迭代器的字节大小以及指向在所述 void* 上执行标准迭代函数(例如递增、递减、 MagicIterator 假定将给定迭代器 memcpy 到内部缓冲区中是安全的,并通过将其自己的缓冲区作为 void* 传递给提供的函数来实现其自己的成员,就像它是原始迭代器一样。

然后,容器必须实现静态迭代函数,将提供的 void* 强制转换为 std::list::iterator。Container::begin() 和 Container::end() 只是构造一个 std::list::iterator,将指向它的指针及其迭代函数表传递到 MagicIterator 中,然后返回 MagicIterator。

这有点令人恶心,并且打破了我关于“no memcpy()”的原始规则,并对相关迭代器的内部结构做出了假设。但它避免了堆分配,保持 Collection 的内部结构(包括 Item)私有,使 MagicIterator 完全独立于所讨论的集合和 IInterface*,并且理论上允许 MagicIterators 与任何集合一起工作(前提是它的迭代器可以安全地 memcopy()' d).