如何避免代码重复实现常量和非常量迭代器?
我正在实现一个类似STL的接口的自定义容器。 我必须提供一个常规的迭代器和一个常量迭代器。 迭代器的两个版本的大部分代码是相同的。 我怎样才能避免这种重复?
例如,我的容器类是Foo
,我正在实现FooIterator
和FooConstIterator
。 这两个迭代器都必须提供像operator++()
这样的方法,它们是相同的。
我的问题类似于如何删除类似的const和非const成员函数之间的代码重复? ,但是这个答案是特定于const和非const方法的,特别是访问器。 我不明白这是如何推广到迭代器的问题。
我应该让FooIterator
从FooIterator
派生,并用额外的非const方法扩展吗? 这要么导致虚拟方法或方法隐藏,这在这里看起来不合适。
也许FooIterator
应该包含一个FooConstIterator
。 虽然这种方法确实减less了重复实施,但似乎重新引入了很多样板方法的定义。
是否有巧妙的模板技术从一个单一的定义生成两个迭代器? 或者也许有一种方式 – 不寒而栗 – 使用预处理器来消除这些几乎相同的类。
我试着看看我的本地STL实现,看看它是如何处理这个。 有这么多的帮助类,我有困难的devise,但它看起来像function只是重复。
在以前的项目中,我的自定义容器是build立在标准STL容器之上的,所以我不必提供自己的迭代器。 在这种情况下,这不是一个选项。
[最好的答案是,不幸的是,由主持人删除,因为这是一个链接的答案。 我明白为什么只有链接的答案是不鼓励的; 删除它,但是,抢劫未来的求职者非常有用的信息。 这个链接已经稳定了七年多了,并且在写这篇文章的时候还在继续。
我强烈推荐Matt Austern博士原创的Dobb's Journal博士的文章“The Standard Librarian:Defining Iterators and Const Iterators” ,2001年1月。如果这个环节不好,现在Dobb博士已经停止运作, 在这里也可以。
为了防止这个replace答案被删除,我将总结解决scheme。
这个想法是一次性实现迭代器作为模板,它需要一个额外的模板参数,一个布尔值,说明这是否是const版本。 在常量和非常量版本不同的实现中,您可以使用模板机制来select正确的代码。 马特·奥斯特的机制被称为choose
。 它看起来像这样:
template <bool flag, class IsTrue, class IsFalse> struct choose; template <class IsTrue, class IsFalse> struct choose<true, IsTrue, IsFalse> { typedef IsTrue type; }; template <class IsTrue, class IsFalse> struct choose<false, IsTrue, IsFalse> { typedef IsFalse type; };
如果你对const和non-const迭代器有不同的实现,那么const实现将包含如下的typedefs:
typedef const T &reference; typedef const T *pointer;
而非常量的实现将会有:
typedef T &reference; typedef T *pointer;
但是随着choose
,你可以有一个基于额外的模板参数select的实现:
typedef typename choose<is_const, const T &, T &>::type reference; typedef typename choose<is_const, const T *, T *>::type pointer;
通过使用底层types的typedef,所有的迭代器方法都可以有相同的实现。 请看Matt Austern的完整例子 。
除了build议你可以对常量和非常量进行模板化之外,还可以通过查看Boost.Iterator教程来减less工作量,该教程也提到了相同的解决scheme。
你可以使用CRTP和一个通用的基础来“注入”方法(但是你仍然需要在当前C ++中复制ctors),或者只是使用预处理器(不需要颤抖;轻松处理ctors):
struct Container { #define G(This) \ This operator++(int) { This copy (*this); ++*this; return copy; } // example of postfix++ delegating to ++prefix struct iterator : std::iterator<...> { iterator& operator++(); G(iterator) }; struct const_iterator : std::iterator<...> { const_iterator& operator++(); G(const_iterator) }; #undef G // G is "nicely" scoped and treated as an implementation detail };
使用std :: iterator,它提供的types定义以及可能提供的任何其他types定义,以使macros直接前进。
STL使用inheritance
template<class _Myvec> class _Vector_iterator : public _Vector_const_iterator<_Myvec>