![](/img/trans.png)
[英]How can I check that assignment of const_reverse_iterator to reverse_iterator is invalid?
[英]How do I apply the DRY principle to iterators in C++? (iterator, const_iterator, reverse_iterator, const_reverse_iterator)
好的,所以我現在有兩個(完全不相關的,不同的項目)類使用迭代器。 一個讓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附帶的頭文件是徒勞的 - 它們並不完全是我正在尋找的教程。
有時,對於那些不熟悉的人來說,全面應用所謂的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適用於此。
一旦我使用以下方法:
對於“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.