C++迭代适配器包装和皮革内迭代和转换的迭代的类型
题
具有玩弄这个我怀疑它是不是远可能的,但我想我会要求的专家。我有以下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; };
我想添加这些方法容器:
MagicIterator<IInterface*> Begin(); MagicIterator<IInterface*> End();
为了呼叫者可以这样写:
Container c = [...] for (MagicIterator<IInterface*> i = c.Begin(); i != c.End(); i++) { IInterface* pItf = *i; [...] }
所以基本上我希望提供一个类似乎是循环的一些收集的(这叫的开始()and End()不允许见)的模球,但它实际上是循环的集合的指针到其他目的(私人的容器类),这可以转变成模的指针。
几个关键点:
MagicIterator
是要被定义之外Container
.Container::Item
必须仍然是私有的。
MagicIterator
有迭代IInterface
指针,尽管事实上,Container
拥有一个std::list<Container::Item>
.Container::Item
包含一个Object*
, ,Object
可以被用来获取IInterface*
.
MagicIterator
有可重复使用的几类类似于容器,但可能会内部有不同的列表,实现持不同的对象(std::vector<SomeOtherItem>
,mylist<YetAnotherItem>
)和与IInterface*
获得在一个不同的方式每次。
MagicIterator
不应该容器包含特定的代码,虽然它可能代表这类做,前提是这些代表团不是硬盘编码的特别容器内部MagicIterator
(所以某种程度上是自动解决编译器,例)。
- 该解决方案必须编制下的视觉C++没有使用其他库(诸如提高),这将需要许可协议,从他们的作者。
- 此外,迭代可能没有分配任何堆存储器(因此没有
new()
或malloc()
在任何阶段),没有memcpy()
.
感谢您的时间,甚至如果你只是读;这个人真的一直困扰着我!
更新: 虽然我已经有一些非常有趣的答案,没有满足所有上述要求。值得注意的是棘手的领域i)耦MagicIterator从容器中以某种方式(默认的模板的论点不剪),并二)避免堆分配;但是我真的后一种解决方案,它涵盖以上所有的子弹。
解决方案 6
我现在找到一个解决方案,它是更为我原来的目的。我还是不喜欢它虽然:)
该解决方案涉及MagicIterator正模板上的模*和正在建造两个void*一个迭代,字节的尺寸的说迭代表指针的职能,执行标准的迭代职能在上述void*如增量,减量,引用,等等。MagicIterator假定它是安全的memcpy给定的迭代进入一个内部缓冲区,并实现其自己的成员通过其自己的缓冲区为无效*要提供的功能,如果它是原始的迭代器。
容器然后有实施的静态迭代的职能铸回提供void*为std::list::迭代器。集装箱::开始()以及集装箱::结束()只是构建一种标准::list::迭代,通过一个指向它变成一个MagicIterator沿用一个表,其迭代的职能,并返回MagicIterator.
这有点恶心,打破了我原来的规则关于"不memcpy()",并且使假设有关的内部迭代的问题。但它避免了堆分配,保持收集的内部(包括项目)私人的,呈现MagicIterator完全独立的集中问题和模*,并在理论上允许MagicIterators工作的任何集合(提供其迭代可以被安全地用存储器复制()'d)。
其他提示
我觉得你们两个单独的问题:
第一,创建一个迭代将返回 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(); }
};
你会创造这种类型的内在 Container
和返回在从它的 begin()
和 end()
方法。
第二,你想要的运行时间-多形态 MagicIterator
.这是什么 any_iterator
不。的 MagicIterator<IInterface*>
只是 any_iterator<IInterface*, boost::forward_traversal_tag, IInterface*>
, , cont_iter
可以就分配给它。
听起来不太复杂的。你可以定义的迭代外。你也可以使用函数.像这样的东西会适合我的想法。注意,这将是方式更清洁,如果这MagicIterator会 不 一个免费的模板,而是一个成员的项目,typedefed在容器也许。因为它是现在,有一个循环基准,这使它necassary写一些丑陋的解决办法的代码。
namespace detail {
template<typename T, typename U>
struct constify;
template<typename T, typename U>
struct constify<T*, U*> {
typedef T * type;
};
template<typename T, typename U>
struct constify<T*, U const*> {
typedef T const * type;
};
}
template<typename DstType,
typename Container,
typename InputIterator>
struct MagicIterator;
class Container
{
private:
struct Item
{
Object* pObject;
};
std::list<Item> m_items;
public:
// required by every Container for the iterator
typedef std::list<Item> iterator;
typedef std::list<Item> const_iterator;
// convenience declarations
typedef MagicIterator< IInterface*, Container, iterator >
item_iterator;
typedef MagicIterator< IInterface*, Container, const_iterator >
const_item_iterator;
item_iterator Begin();
item_iterator End();
};
template<typename DstType,
typename Container = Container,
typename InputIterator = typename Container::iterator>
struct MagicIterator :
// pick either const T or T, depending on whether it's a const_iterator.
std::iterator<std::input_iterator_tag,
typename detail::constify<
DstType,
typename InputIterator::value_type*>::type> {
typedef std::iterator<std::input_iterator_tag,
typename detail::constify<
DstType,
typename InputIterator::value_type*>::type> base;
MagicIterator():wrapped() { }
explicit MagicIterator(InputIterator const& it):wrapped(it) { }
MagicIterator(MagicIterator const& that):wrapped(that.wrapped) { }
typename base::value_type operator*() {
return (*wrapped).pObject->GetInterface();
}
MagicIterator& operator++() {
++wrapped;
return *this;
}
MagicIterator operator++(int) {
MagicIterator it(*this);
wrapped++;
return it;
}
bool operator==(MagicIterator const& it) const {
return it.wrapped == wrapped;
}
bool operator!=(MagicIterator const& it) const {
return !(*this == it);
}
InputIterator wrapped;
};
// now that the iterator adepter is defined, we can define Begin and End
inline Container::item_iterator Container::Begin() {
return item_iterator(m_items.begin());
}
inline Container::item_iterator Container::End() {
return item_iterator(m_items.end());
}
现在,开始使用它:
for(MagicIterator<IInterface*> it = c.Begin(); it != c.End(); ++it) {
// ...
}
你也可以使用一个迭代混合提供通过提升,这样工作输入版本的提升::function_output_iterator.它叫你迭代的 operator()
然后返回适当的价值,做我们做什么上我们的 operator*
原则。你找到它 random/detail/iterator_mixin.hpp
.这大概会导致较少的代码。但是,这也需要来毁坏我们的颈部,以确保朋友的东西,因为项目是私人和迭代的不是内定义的项目。不管怎样,祝你好运:)
创建一个抽象 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;
};
和一个 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.
(你可以做 IteratorImplementation
一类"内部" Iterator
保持整洁。)
在你 Container
类,返回的一个实例 Iterator
有一个亚类的定义 IteratorImplementation
在 ctor
:
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);
}
这真的取决于 Container
, 因为回归的价值观的 c.Begin()
和 c.End()
是执行定义。
如果一系列可能的 Container
s知 MagicIterator
, ,一个包装类可使用。
template<typename T>
class MagicIterator
{
public:
MagicIterator(std::vector<T>::const_iterator i)
{
vector_const_iterator = i;
}
// Reimplement similarly for more types.
MagicIterator(std::vector<T>::iterator i);
MagicIterator(std::list<T>::const_iterator i);
MagicIterator(std::list<T>::iterator i);
// Reimplement operators here...
private:
std::vector<T>::const_iterator vector_const_iterator;
std::vector<T>::iterator vector_iterator;
std::list<T>::const_iterator list_const_iterator;
std::list<T>::iterator list_iterator;
};
的 容易的 办法将是使用一个模板,其中接受 Container
's type:
// C++0x
template<typename T>
class Iterator :
public T::iterator
{
using T::iterator::iterator;
};
for(Iterator<Container> i = c.begin(); i != c.end(); ++i)
{
// ...
}
我看不出有任何理由为什么你不能执行这正是因为你已经奠定了出来...我失去了一些东西?
到澄清,则需要把某种访问方法在你的容器类。他们可以是私有的,你可以宣布MagicIterator作为一个朋友,如果你觉得这是最好的办法来封装,但我会让他们直接。这些访问方法会使用正常的STL迭代的内容和执行转换为模.因此迭代将实际完成与容器的存取方法和MagicIterator将只是一种代理的对象,使它更加容易。让它折返,你可以有MagicIterator通过在某种ID看了STL迭代的内容,或者实际上,你可以拥有它通过STL作为一个迭代 void *
.
访问者可以是一个简单的(和因此更容易维护)的解决方案。