好的,所以我现在有两个(完全不相关的,不同的项目)类使用迭代器。一个有iterator
和reverse_iterator
按预期工作,另一个,当前一个有iterator
和半破const_iterator
(具体来说,因为const_iterator派生自迭代器,代码LinkedList<int>::iterator i = const_list.begin()
有效,允许您修改const定义列表...)
我打算将所有四种类型添加到这个类......如果可以的话。
如何继续最小化复制/粘贴代码并仅更改返回类型?创建一个像base_iterator
这样的基类继承?创建iterator
或const_iterator
并从中继承?从某些std :: class继承?如果这些案例中的任何一个是“最佳”方法,那么代码会在哪里?
也许没有其他选择是好的?我在这里迷路了,找不到太多的参考资料。
任何建议都值得赞赏,但请记住,我是这个主题的新手(通常是迭代器和C ++,尤其是OOP)。我试图研究GCC附带的头文件是徒劳的 - 它们并不完全是我正在寻找的教程。
答案 0 :(得分:3)
有时,对于那些不熟悉的人来说,全面应用所谓的DRY规则(Don't Repeat Yourself)并不是最好的方法。特别是如果你是语言(C ++和迭代器)和OOP本身(方法论)的新手,那么尝试最小化你现在需要编写的代码量几乎没有什么好处。
我将使用适当的代码为每个迭代器实现两个迭代器。也许在您对语言,工具和技术有更多经验之后,然后会回过头来看看您是否可以通过分解公共代码来减少代码量。
答案 1 :(得分:3)
实际上非常简单。
首先,看一下Boost.Iterator库。
第二:你需要声明一个基类(在例子中很好地解释了如何继续),它将与此类似。
template <class Value>
class BaseIterator: boost::iterator_adaptor< ... > {};
您可以实现操作以在此处移动指针。请注意,因为它是对现有迭代器的改编,所以只需几次笔画即可实现。这真是令人印象深刻。
第三,你只需使用const和非const版本来键入它:
typedef BaseIterator<Value> iterator;
typedef BaseIterator<const Value> const_iterator;
图书馆明确告诉您如何使const_iterator
版本可以从iterator
版本构建。
第四,反过来说,有一个特殊的reverse_iterator对象,它构建在常规迭代器上并向后移动:)
总而言之,这是一种在自定义类上定义迭代器的非常优雅但功能齐全的方法。
我经常编写自己的容器适配器,而不仅仅是为了节省自己的打字而不是DRY!
答案 2 :(得分:1)
使迭代器派生自const_iterator而不是相反。适当地使用const_cast
(作为实现细节,不向用户提供)。这在直接“迭代器是const_iterators”的简单情况和模型中非常有效。
当启动以在代码中要求澄清注释时,请编写单独的类。您可以使用本地化的宏为您生成类似的代码,以避免重复逻辑:
struct Container {
#define G(This) \
This& operator++() { ++_internal_member; return *this; } \
This operator++(int) { This copy (*this); ++*this; return copy; }
struct iterator {
G(iterator)
};
struct const_iterator {
G(const_iterator)
const_iterator(iterator); // and other const_iterator specific code
};
#undef G
};
宏的作用域/本地化很重要,当然,只有在它真正帮助你的情况下才使用它 - 如果它导致代码不太可读,请明确键入它。
关于反向迭代器:在许多情况下,你可以使用std::reverse_iterator
包装你的“普通”迭代器,而不是重写它们。
struct Container {
struct iterator {/*...*/};
struct const_iterator {/*...*/};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
};
答案 3 :(得分:0)
LinkedList<int>::iterator i = const_list.begin()
您的开始方法是什么样的?通过研究STL,您可以看到容器定义了两个具有以下签名的方法:
const_iterator begin() const;
iterator begin();
从限定为const的对象中获取iterator
应该没有问题。我不认为DRY适用于此。
答案 4 :(得分:0)
一旦我使用了以下方法:
对于“iterator”,附加的构造函数将替换默认的复制构造函数,在我的例子中,它等同于默认的复制构造函数。
对于“const_iterator”,它将是一个额外的构造函数,允许从“iterator”构造“const_iterator”
答案 5 :(得分:0)
what maxim1000 suggested的更具体版本:
#include <type_traits>
template<typename Container, bool forward>
class iterator_base
{
public:
using value_type =
typename std::conditional<std::is_const<Container>::value,
const typename Container::value_type,
typename Container::value_type>::type;
iterator_base() { }
// For conversions from iterator to const_iterator.
template<typename U>
iterator_base(const iterator_base<U, forward>& other)
: c(other.c)
{
// ....
}
value_type& operator*() const
{
// ...
}
iterator_base& operator++()
{
if (forward)
{
// ...
}
else
{
// ...
}
}
iterator_base& operator++(int)
{
iterator_base copy(*this);
++*this;
return copy;
}
private:
Container* c = nullptr;
// ...
};
using iterator = iterator_base<self_type, true>;
using const_iterator = iterator_base<const self_type, true>;
using reverse_iterator = iterator_base<self_type, false>;
using const_reverse_iterator = iterator_base<const self_type, false>;