c++ - std::find 不能用自定义迭代器编译
问题描述
我发现了一个带有迭代器的实验性循环缓冲区实现,如下所示:
struct my_iterator
{
using iterator_category = std::random_access_iterator_tag;
using difference_type = long long;
using reference = typename std::conditional_t< isconst, T const &, T & >;
using pointer = typename std::conditional_t< isconst, T const *, T * >;
using vec_pointer = typename std::conditional_t<isconst, std::vector<T> const *, std::vector<T> *>;
...
pointer operator->() { return &(operator *()); }
my_iterator& operator++ ()
{
++index;
return *this;
};
my_iterator operator ++(int)
{
my_iterator iter = *this;
++index;
return iter;
}
...
};
在此处查看完整的源代码。
迭代器的实现有点奇怪,但至少它适用于基于范围的循环。唯一的问题是它不能编译std::find
:
ring<int> mybuf(10);
auto i = std::find(mybuf.begin(), mybuf.end(), 100);
GCC9 显示以下错误:
/usr/include/c++/9/bits/stl_algo.h: In instantiation of ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = ring<int>::my_iterator<false>; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const int>]’:
/usr/include/c++/9/bits/stl_algo.h:3938:28: required from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = ring<int>::my_iterator<false>; _Tp = int]’
/home/def/repos/Awl/Tests/RingTest.cpp:71:60: required from here
/usr/include/c++/9/bits/stl_algo.h:162:34: error: no matching function for call to ‘__iterator_category(ring<int>::my_iterator<false>&)’
162 | std::__iterator_category(__first));
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/usr/include/c++/9/bits/stl_iterator_base_types.h:205:5: note: candidate: ‘template<class _Iter> constexpr typename std::iterator_traits<_Iterator>::iterator_category std::__iterator_category(const _Iter&)’
205 | __iterator_category(const _Iter&)
它与某些东西有关,iterator_category
但尚不清楚它有什么问题。
编辑1:
完整源代码:
#include <stdexcept>
#include <cassert>
#include <vector>
#include <initializer_list>
template <class T>
class ring
{
using value_type = T;
using reference = T & ;
using const_reference = const T &;
using size_type = size_t;
using circularBuffer = std::vector<value_type>;
circularBuffer m_array;
size_type m_head;
size_type m_tail;
size_type m_contents_size;
size_type m_array_size;
template <bool isconst> struct my_iterator;
public:
ring(size_type size) :
m_array(size),
m_array_size(size),
m_head(1),
m_tail(0),
m_contents_size(0)
{
assert(m_array_size > 1 && "size must be greater than 1");
}
ring(std::initializer_list<T> l) :
m_array(l),
m_array_size(l.size()),
m_head(0),
m_tail(l.size() - 1),
m_contents_size(l.size())
{
assert(m_array_size > 1 && "size must be greater than 1");
}
reference front() { return m_array[m_head]; }
reference top() { return front(); }
reference back() { return m_array[m_tail]; }
const_reference front() const { return m_array[m_head]; }
const_reference back() const { return m_array[m_tail]; }
void clear();
void push_back(const value_type &item);
void push(const value_type &item) { push_back(item); }
void pop_front() { increment_head(); }
void pop() { pop_front(); }
size_type size() const { return m_contents_size; }
size_type capacity() const { return m_array_size; }
bool empty() const;
bool full() const;
size_type max_size() const { return size_type(-1) / sizeof(value_type); }
reference operator[](size_type index);
const_reference operator[](size_type index) const;
reference at(size_type index);
const_reference at(size_type index) const;
using iterator = my_iterator<false>;
using const_iterator = my_iterator<true>;
iterator begin();
const_iterator begin() const;
const_iterator cbegin() const;
iterator rbegin();
const_iterator rbegin() const;
iterator end();
const_iterator end() const;
const_iterator cend() const;
iterator rend();
const_iterator rend() const;
private:
void increment_tail();
void increment_head();
template <bool isconst = false>
struct my_iterator
{
using iterator_category = std::random_access_iterator_tag;
using difference_type = long long;
using reference = typename std::conditional_t< isconst, T const &, T & >;
using pointer = typename std::conditional_t< isconst, T const *, T * >;
using vec_pointer = typename std::conditional_t<isconst, std::vector<T> const *, std::vector<T> *>;
private:
vec_pointer ptrToBuffer;
size_type offset;
size_type index;
bool reverse;
bool comparable(const my_iterator & other) {
return (reverse == other.reverse);
}
public:
my_iterator() : ptrToBuffer(nullptr), offset(0), index(0), reverse(false) {} //
my_iterator(const ring<T>::my_iterator<false>& i) :
ptrToBuffer(i.ptrToBuffer),
offset(i.offset),
index(i.index),
reverse(i.reverse) {}
reference operator*() {
if (reverse)
return (*ptrToBuffer)[(ptrToBuffer->size() + offset - index) % (ptrToBuffer->size())];
return (*ptrToBuffer)[(offset + index) % (ptrToBuffer->size())];
}
reference operator[](size_type index) {
my_iterator iter = *this;
iter.index += index;
return *iter;
}
pointer operator->() { return &(operator *()); }
my_iterator& operator++ ()
{
++index;
return *this;
};
my_iterator operator ++(int)
{
my_iterator iter = *this;
++index;
return iter;
}
my_iterator& operator --()
{
--index;
return *this;
}
my_iterator operator --(int) {
my_iterator iter = *this;
--index;
return iter;
}
friend my_iterator operator+(my_iterator lhs, int rhs) {
lhs.index += rhs;
return lhs;
}
friend my_iterator operator+(int lhs, my_iterator rhs) {
rhs.index += lhs;
return rhs;
}
my_iterator& operator+=(int n) {
index += n;
return *this;
}
friend my_iterator operator-(my_iterator lhs, int rhs) {
lhs.index -= rhs;
return lhs;
}
friend difference_type operator-(const my_iterator& lhs, const my_iterator& rhs) {
lhs.index -= rhs;
return lhs.index - rhs.index;
}
my_iterator& operator-=(int n) {
index -= n;
return *this;
}
bool operator==(const my_iterator &other)
{
if (comparable(other))
return (index + offset == other.index + other.offset);
return false;
}
bool operator!=(const my_iterator &other)
{
if (comparable(other)) return !this->operator==(other);
return true;
}
bool operator<(const my_iterator &other)
{
if (comparable(other))
return (index + offset < other.index + other.offset);
return false;
}
bool operator<=(const my_iterator &other)
{
if (comparable(other))
return (index + offset <= other.index + other.offset);
return false;
}
bool operator >(const my_iterator &other)
{
if (comparable(other)) return !this->operator<=(other);
return false;
}
bool operator>=(const my_iterator &other)
{
if (comparable(other)) return !this->operator<(other);
return false;
}
friend class ring<T>;
};
};
template<class T>
void ring<T>::push_back(const value_type & item)
{
increment_tail();
if (m_contents_size > m_array_size) increment_head(); // > full, == comma
m_array[m_tail] = item;
}
template<class T>
void ring<T>::clear()
{
m_head = 1;
m_tail = m_contents_size = 0;
}
template<class T>
bool ring<T>::empty() const
{
if (m_contents_size == 0) return true;
return false;
}
template<class T>
inline bool ring<T>::full() const
{
if (m_contents_size == m_array_size) return true;
return false;
}
template<class T>
typename ring<T>::const_reference ring<T>::operator[](size_type index) const
{
index += m_head;
index %= m_array_size;
return m_array[index];
}
template<class T>
typename ring<T>::reference ring<T>::operator[](size_type index)
{
const ring<T>& constMe = *this;
return const_cast<reference>(constMe.operator[](index));
// return const_cast<reference>(static_cast<const ring<T>&>(*this)[index]);
}
//*/
template<class T>
typename ring<T>::reference ring<T>::at(size_type index)
{
if (index < m_contents_size) return this->operator[](index);
throw std::out_of_range("index too large");
}
template<class T>
typename ring<T>::const_reference ring<T>::at(size_type index) const
{
if (index < m_contents_size) return this->operator[](index);
throw std::out_of_range("index too large");
}
template<class T>
typename ring<T>::iterator ring<T>::begin()
{
iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = 0;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::begin() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = 0;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::cbegin() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = 0;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::iterator ring<T>::rbegin()
{
iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_tail;
iter.index = 0;
iter.reverse = true;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::rbegin() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_tail;
iter.index = 0;
iter.reverse = true;
return iter;
}
template<class T>
typename ring<T>::iterator ring<T>::end()
{
iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = m_contents_size;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::end() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = m_contents_size;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::cend() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_head;
iter.index = m_contents_size;
iter.reverse = false;
return iter;
}
template<class T>
typename ring<T>::iterator ring<T>::rend()
{
iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_tail;
iter.index = m_contents_size;
iter.reverse = true;
return iter;
}
template<class T>
typename ring<T>::const_iterator ring<T>::rend() const
{
const_iterator iter;
iter.ptrToBuffer = &m_array;
iter.offset = m_tail;
iter.index = m_contents_size;
iter.reverse = true;
return iter;
}
template<class T>
void ring<T>::increment_tail()
{
++m_tail;
++m_contents_size;
if (m_tail == m_array_size) m_tail = 0;
}
template<class T>
void ring<T>::increment_head()
{
if (m_contents_size == 0) return;
++m_head;
--m_contents_size;
if (m_head == m_array_size) m_head = 0;
}
int main()
{
ring<int> mybuf(10);
auto i = std::find(mybuf.begin(), mybuf.end(), 100);
return 0;
}
解决方案
推荐阅读
- powershell - 如何创建具有相同触发器的任务?
- android - 自定义按钮未完全显示
- swift - Swift FSCalendar Interactive Scope Gesture 以编程方式
- sql - 从关系数据库表构建自定义 JSON
- flutter - ListView Flutter 的单选
- reactjs - 整个页面重新渲染,而不仅仅是包含更新属性的组件
- python - 由于网络抓取中的编码,乱码文本输出
- r - 如何计算多个数据系列中的曲线下面积(AUC)?
- python - 在输出到控制台之前在 Spark Structured Streaming 上处理数据
- mongodb - 在 MongoDb 聚合框架中应用多阶段分组