如何在C ++中将DRY原则应用于迭代器? (iterator,const_iterator,reverse_iterator,const_reverse_iterator)

时间:2009-11-21 20:17:09

标签: c++ inheritance iterator dry code-reuse

好的,所以我现在有两个(完全不相关的,不同的项目)类使用迭代器。一个有iteratorreverse_iterator按预期工作,另一个,当前一个有iterator和半破const_iterator(具体来说,因为const_iterator派生自迭代器,代码LinkedList<int>::iterator i = const_list.begin()有效,允许您修改const定义列表...) 我打算将所有四种类型添加到这个类......如果可以的话。

如何继续最小化复制/粘贴代码并仅更改返回类型?创建一个像base_iterator这样的基类继承?创建iteratorconst_iterator并从中继承?从某些std :: class继承?如果这些案例中的任何一个是“最佳”方法,那么代码会在哪里? 也许没有其他选择是好的?我在这里迷路了,找不到太多的参考资料。

任何建议都值得赞赏,但请记住,我是这个主题的新手(通常是迭代器和C ++,尤其是OOP)。我试图研究GCC附带的头文件是徒劳的 - 它们并不完全是我正在寻找的教程。

6 个答案:

答案 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)

一旦我使用了以下方法:

  1. 制作模板类common_iterator
  2. 为“iterator”和“const_iterator”添加typedef
  3. 向“common_iterator”添加一个采用“iterator”类型
  4. 的构造函数

    对于“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>;