簡體   English   中英

如何在C ++中將DRY原則應用於迭代器? (iterator,const_iterator,reverse_iterator,const_reverse_iterator)

[英]How do I apply the DRY principle to iterators in C++? (iterator, const_iterator, reverse_iterator, const_reverse_iterator)

好的,所以我現在有兩個(完全不相關的,不同的項目)類使用迭代器。 一個讓iteratorreverse_iterator按預期工作,另一個,當前的有iterator和半破壞的const_iterator (具體來說,因為const_iterator派生自迭代器,代碼LinkedList<int>::iterator i = const_list.begin()是有效的並允許您修改const定義列表...)。
我打算將所有四種類型添加到這個類......如果可以的話。

我如何繼續最小化復制/粘貼代碼並僅更改返回類型? 創建一個像base_iterator這樣的基類來繼承嗎? 創建一個iteratorconst_iterator並從中繼承? 從某些std :: class繼承? 如果這些案例中的任何一種都是“最佳”方法,那么代碼會在哪里?
也許沒有其他選擇是好的? 我在這里迷路了,找不到太多的參考資料。

任何建議都表示贊賞,但請記住,我是這個主題的新手(通常是迭代器和C ++,尤其是OOP)。 我試圖研究GCC附帶的頭文件是徒勞的 - 它們並不完全是我正在尋找的教程。

有時,對於那些不熟悉的人來說,全面應用所謂的DRY規則( 不要重復自己 )並不是最好的方法。 特別是如果你是新來的語言(C ++和迭代器)和OOP本身(方法),還有在試圖最小化的代碼,你現在需要寫的金額沒有什么好處。

我將使用適當的代碼為每個迭代器實現兩個迭代器。 也許在您對語言,工具和技術有更多經驗之后,請回過頭來看看您是否可以通過分解公共代碼來減少代碼量。

它實際上非常簡單。

首先,看看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對象,它建立在常規迭代器上並向后移動:)

總而言之,這是一種在自定義類上定義迭代器的非常優雅且功能齊全的方法。

我經常寫自己的容器適配器,而不是簡單地保存自己的一些打字!

使迭代器派生自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;
};

LinkedList<int>::iterator i = const_list.begin()你的begin方法是什么樣的? 通過研究STL,您可以看到容器定義了兩個具有以下簽名的方法:

const_iterator begin() const;
iterator begin();

從限定為const的對象獲取iterator應該沒有問題。 我不認為DRY適用於此。

一旦我使用以下方法:

  1. 制作模板類common_iterator
  2. 為“iterator”和“const_iterator”添加typedef
  3. 將“common_iterator”添加到采用“迭代器”類型的構造函數中

對於“iterator”,附加的構造函數將替換默認的復制構造函數,在我的例子中它等同於默認的復制構造函數。

對於“const_iterator”,它將是一個額外的構造函數,允許從“iterator”構造“const_iterator”

maxim1000建議的更具體的版本:

#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>;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM