我实现了一个迭代器包装类,它将每个步骤的基础random_access_iterator
移动一定量/步长S
。
Wrapper<Iterator> + i === Iterator + i*S
它集合了某种“每N th 元素迭代器”。
基本思想是迭代连续存储矩阵的列或对角线:
/*
0 1 2
3 4 5
6 7 8
*/
当S为4时,我们可以使用Wrapper
[Wrapper::begin]=0 -> 4 -> 8 -> 12=[Wrapper::end]
或使用S=3
[Wrapper::begin]=1 -> 4 -> 7 -> 10=[Wrapper::end]
的第二列迭代对角线
它几乎与end
迭代器的问题一起使用。生成的end()
迭代器可能是> last+1
(UB?)。
如果检查的迭代器与Wrapper
一起使用,则会失败,因为它们将检测到最后一步超出基础迭代范围的有效范围[begin,end]
。
除了使Wrapper
本身成为某种检查迭代器,即包含对有效end
的引用之外,是否有任何理智,高效的方法来解决这个问题:
Wrapper<Iterator> & operator++ ()
{
m_it += std::min(S, std::distance(m_it, m_end));
return *this;
}
与
Wrapper<Iterator> & operator++ ()
{
m_it += S;
return *this;
}
答案 0 :(得分:2)
你几乎找到了解决方案;由于STL迭代器的设计很差,所需的迭代器需要包含当前迭代器和结束迭代器。
如果唯一的应用程序迭代在连续存储的矩阵上,并且迭代器本身绑定到矩阵(例如列迭代器),并且矩阵不是太大,那么您可以简单地确保有一个底层连续内存中的附加行,例如对于4x4矩阵,分配20个条目。
答案 1 :(得分:0)
跳转到底层结构的真实 end
而不是迭代它的方法,有一个缺点,需要额外的诊断才能工作bidirectional
或以random access
方式。
问问题operator++
:
Wrapper<Iterator> & operator++ ()
{
m_it += std::min(S, std::distance(m_it, m_end));
return *this;
}
对于示例矩阵,使用S=3
operator++
迭代第二列
[Wrapper :: begin] = 1 - &gt; 4 - &gt; 7 - &gt; 9 = [Wrapper :: end == real end
]
现在,如果operator-
使用operator--
或operator[]
或9-7 != S
等,则需要知道如何返回实际列。
而不是包含'真实'end
迭代器,它需要额外的信息才能行走'双向'(或以随机访问方式),Wrapper
迭代器可以增加偏移O
而不是底层迭代器本身,并且只在解除引用时推进迭代器。
template<class BaseIterator,
typename std::enable_if<
std::is_same<
typename BaseIterator::iterator_category,
std::random_access_iterator_tag
>::value
>::type * = 0>
class RASItWrapper
: public std::iterator_traits<BaseIterator>
{
BaseIterator m_it;
difference_type S, O;
public:
// ...
RASItWrapper & operator++ ()
{ // increment then return
O += S;
return *this;
}
// ...
reference operator* () const { return *(m_it + O); }
pointer operator->() const { return (m_it + O).operator->(); }
reference operator[] (difference_type const & i) const
{
return (m_it + O)[i*N];
}
// ...
bool operator== (RASItWrapper const &rhs) const
{ // perhaps only compare O since comparing different ranges is meaningless
return m_it == rhs.m_it && O == rhs.O;
}
// ...
};