问题描述
玩弄了这个,我怀疑这是不可能的,但我想我会问专家.我有以下 C++ 代码:
I类接口{虚拟 void SomeMethod() = 0;};类对象{IInterface* GetInterface() { ... }};类容器{私人的:结构项目{对象* pObject;[... 其他成员 ...]};std::list<项目>m_items;};我想将这些方法添加到 Container 中:
MagicIterator<IInterface*>开始();MagicIterator<IInterface*>结尾();为了让调用者可以写:
容器 c = [...]for (MagicIterator i = c.Begin(); i != c.End(); i++){IInterface* pItf = *i;[...]}所以本质上我想提供一个类,它似乎在迭代 IInterface 指针的某些集合(不允许 Begin() 和 End() 的调用者看到),但实际上是在迭代指向可以转换为 IInterface 指针的其他对象(Container 类私有)的指针.
几个关键点:
MagicIterator
将被定义在Container
之外.Container::Item
必须保持私有.
MagicIterator
必须迭代IInterface
指针,尽管Container
拥有std::list<Container::项目>
.Container::Item
包含一个Object*
,Object
可用于获取IInterface*
.
MagicIterator
必须可与多个类似于 Container 的类重用,但在内部可能有不同的列表实现来保存不同的对象(std::vector
、mylist
) 并且每次都以不同的方式获得IInterface*
.
MagicIterator
不应包含特定于容器的代码,尽管它可以委托给这样做的类,前提是此类委托没有硬编码到MagicIterator
内的特定容器(因此例如,编译器会以某种方式自动解析).
- 该解决方案必须在 Visual C++ 下编译,不得使用其他库(例如 boost),这需要其作者的许可协议.
- 此外,迭代可能不会分配任何堆内存(因此在任何阶段都不会分配
new()
或malloc()
),也不会分配memcpy()代码>.
感谢您的宝贵时间,即使您只是在阅读;这个真的烦死我了!
更新:虽然我得到了一些非常有趣的答案,但还没有一个满足上述所有要求.值得注意的是,棘手的领域是 i) 以某种方式将 MagicIterator 从 Container 中解耦(默认模板参数不会削减它),以及 ii) 避免堆分配;但我真的在寻求涵盖上述所有项目符号的解决方案.
我现在找到了一个更适合我最初目的的解决方案.不过我还是不喜欢:)
解决方案涉及在 IInterface* 上对 MagicIterator 进行模板化,并使用指向迭代器的 void*、所述迭代器的字节大小以及指向在所述 void* 上执行标准迭代函数(例如增量)的函数的指针表构造,递减,取消引用等.MagicIterator 假设将给定的迭代器 memcpy 到内部缓冲区是安全的,并通过将自己的缓冲区作为 void* 传递给提供的函数来实现其自己的成员,就好像它是原始迭代器一样.
Container 然后必须实现静态迭代函数,将提供的 void* 转换回 std::list::iterator.Container::begin() 和 Container::end() 只需构造一个 std::list::iterator,将指向它的指针连同其迭代函数表一起传递给 MagicIterator,然后返回 MagicIterator.
这有点恶心,打破了我关于no memcpy()"的原始规则,并对所讨论的迭代器的内部进行了假设.但它避免了堆分配,保持 Collection 的内部(包括 Item)私有,使 MagicIterator 完全独立于所讨论的集合和 IInterface*,并且理论上允许 MagicIterators 与任何集合一起工作(只要它的迭代器可以安全地 memcopy()'d).
Having toyed with this I suspect it isn't remotely possible, but I thought I'd ask the experts. I have the following C++ code:
class IInterface { virtual void SomeMethod() = 0; }; class Object { IInterface* GetInterface() { ... } }; class Container { private: struct Item { Object* pObject; [... other members ...] }; std::list<Item> m_items; };
I want to add these methods to Container:
MagicIterator<IInterface*> Begin(); MagicIterator<IInterface*> End();
In order that callers can write:
Container c = [...] for (MagicIterator<IInterface*> i = c.Begin(); i != c.End(); i++) { IInterface* pItf = *i; [...] }
So essentially I want to provide a class which appears to be iterating over some collection (which the caller of Begin() and End() is not allowed to see) of IInterface pointers, but which is actually iterating over a collection of pointers to other objects (private to the Container class) which can be converted into IInterface pointers.
A few key points:
MagicIterator
is to be defined outsideContainer
.Container::Item
must remain private.
MagicIterator
has to iterate overIInterface
pointers, despite the fact thatContainer
holds astd::list<Container::Item>
.Container::Item
contains anObject*
, andObject
can be used to fetchIInterface*
.
MagicIterator
has to be reusable with several classes which resemble Container, but might internally have different list implementations holding different objects (std::vector<SomeOtherItem>
,mylist<YetAnotherItem>
) and withIInterface*
obtained in a different manner each time.
MagicIterator
should not contain container-specific code, though it may delegate to classes which do, provided such delegation is not hard coded to to particular containers insideMagicIterator
(so is somehow resolved automatically by the compiler, for example).
- The solution must compile under Visual C++ without use of other libraries (such as boost) which would require a license agreement from their authors.
- Also, iteration may not allocate any heap memory (so no
new()
ormalloc()
at any stage), and nomemcpy()
.
Thanks for your time, even if you're just reading; this one's really been bugging me!
Update: Whilst I've had some very interesting answers, none have met all the above requirements yet. Notably the tricky areas are i) decoupling MagicIterator from Container somehow (default template arguments don't cut it), and ii) avoiding heap allocation; but I'm really after a solution which covers all of the above bullets.
I've now found a solution which is fitter for my original purpose. I still don't like it though :)
The solution involves MagicIterator being templated on IInterface* and being constructed with both a void* to an iterator, the byte size of said iterator, and a table of pointers to functions which perform standard iteration functions on said void* such as increment, decrement, dereference, etc. MagicIterator assumes that it is safe to memcpy the given iterator into an internal buffer, and implements its own members by passing its own buffer as a void* to the supplied functions as if it were the original iterator.
Container then has to implement static iteration functions which cast back a supplied void* to a std::list::iterator. Container::begin() and Container::end() simply construct a std::list::iterator, pass a pointer to it into a MagicIterator along with a table of its iteration functions, and return the MagicIterator.
It's somewhat disgusting, and breaks my original rule regarding "no memcpy()", and makes assumptions about the internals of the iterators in question. But it avoids heap allocation, keeps Collection's internals (including Item) private, renders MagicIterator entirely independent of the collection in question and of IInterface*, and in theory allows MagicIterators to work with any collection (provided its iterators can be safely memcopy()'d).
这篇关于一个 C++ 迭代器适配器,它包装和隐藏内部迭代器并转换迭代类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!