I have this code:
template <typename Iter>
class map_iterator : public std::iterator<std::bidirectional_iterator_tag, typename Iter::value_type::second_type> {
public:
map_iterator() {}
map_iterator(Iter j) : i(j) {}
map_iterator& operator++() { ++i; return *this; }
map_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
map_iterator& operator--() { --i; return *this; }
map_iterator operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(map_iterator j) const { return i == j.i; }
bool operator!=(map_iterator j) const { return !(*this == j); }
reference operator*() { return i->second; }
pointer operator->() { return &i->second; }
protected:
Iter i;
};
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) { return map_iterator<Iter>(j); }
using route_departure_container = std::map<packed_time, route_departure_o>;
template <typename Iter>
using route_departure_const_iterator = map_iterator;
template <typename Iter>
route_departure_const_iterator<Iter> departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm);
I am getting compiler errors: syntax error: missing ';' before '*' etc. and C4430 missing type specifier on lines
reference operator*() { return i->second; }
pointer operator->() { return &i->second; }
What is the problem?
Related
I have this code:
template <typename Iter>
class map_iterator : public std::iterator<std::bidirectional_iterator_tag, typename Iter::value_type::second_type> {
public:
map_iterator() {}
map_iterator(Iter j) : i(j) {}
map_iterator& operator++() { ++i; return *this; }
map_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
map_iterator& operator--() { --i; return *this; }
map_iterator operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(map_iterator j) const { return i == j.i; }
bool operator!=(map_iterator j) const { return !(*this == j); }
reference operator*() { return i->second; }
pointer operator->() { return &i->second; }
protected:
Iter i;
};
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) { return map_iterator<Iter>(j); }
using route_departure_container = std::map<packed_time, route_departure_o>;
template <typename Iter>
using route_departure_const_iterator = map_iterator;
route_departure_const_iterator departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm);
I have map using route_departure_container = std::map<packed_time, route_departure_o>; and I want to iterate through this map in a way that the iterator would reference only on the value and not the pair<key, value>.
The problem I have is in the last line route_departure_const_iterator departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm); where route_departure_const_iterator is underlined with red and it says: argument list for alias template "route_departure_const_iterator" is missing.
I tried to insert template <typename Iter> above this line but it did not help. What should I do?
The same way you wrote the above declaration:
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) { return map_iterator<Iter>(j); }
You also need to write your problematic declaration:
template <typename Iter>
route_departure_const_iterator<Iter> departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm);
Because the way you defined route_departure_const_iterator is just a plain, non-const alias to map_iterator, so you use it the same.
I found an experimental circular buffer implementation with an iterator that looks like this:
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;
}
...
};
See the full source code here.
The iterator has a bit strange implementation, but at least it works with range based loops. The only problem is that it does not compile with std::find:
ring<int> mybuf(10);
auto i = std::find(mybuf.begin(), mybuf.end(), 100);
GCC9 shows the following errors:
/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&)
it is something related to iterator_category but it is not clear what wrong with it.
EDIT1:
Full source code :
#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;
}
I tried to implement iterators for a class of mine and surprisingly I got the following:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second
candidate 1: 'Iterator Iterator::operator+(const ptrdiff_t&) [with T = int; ptrdiff_t = long long int]'
candidate 2: 'operator+(int, unsigned int)'
Here's the Iterator code:
template<typename T>
class Iterator {
public:
Iterator(T *p = nullptr) { this->ptr = p; }
Iterator(const Iterator<T>& iter) = default;
Iterator<T>& operator=(const Iterator<T>& iter) = default;
Iterator<T>& operator=(T* p) { this->ptr = p; return *this; }
operator bool() const { return this->ptr ? true : false; }
bool operator==(const Iterator<T>& p) const { return this->ptr == p.getConstPtr(); }
bool operator!=(const Iterator<T>& p) const { return this->ptr != p.getConstPtr(); }
Iterator<T>& operator+=(const ptrdiff_t& v) { this->ptr += v; return *this; }
Iterator<T>& operator-=(const ptrdiff_t& v) { this->ptr -= v; return *this; }
Iterator<T>& operator++() { ++this->ptr; return *this; }
Iterator<T>& operator--() { --this->ptr; return *this; }
Iterator<T> operator++(int) { auto temp(*this); ++this->ptr; return temp; }
Iterator<T> operator--(int) { auto temp(*this); --this->ptr; return temp; }
Iterator<T> operator+(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr += v; auto temp(*this); this->ptr = oldPtr; return temp; }
Iterator<T> operator-(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr -= v; auto temp(*this); this->ptr = oldPtr; return temp; }
ptrdiff_t operator-(const Iterator<T>& p) { return std::distance(p.getPtr(), this->getPtr()); }
T& operator*() { return *(this->ptr); }
const T& operator*() const { return *(this->ptr); }
T* operator->() { return this->ptr; }
T* getPtr() const { return this->ptr; }
const T* getConstPtr() const { return this->ptr; }
private:
T *ptr;
};
And here's how I typedef it inside my class:
template<typename T>
class ExampleClass {
public:
// ...
typedef Iterator<T> iterator;
typedef Iterator<const T> const_iterator;
// ...
iterator begin() { return iterator(&this->ptr()[0]); }
iterator end() { return iterator(&this->ptr()[this->size()]); }
const_iterator cbegin() { return const_iterator(&this->ptr()[0]); }
const_iterator cend() { return const_iterator(&this->ptr()[this->size()]); }
// ...
// A function where I use the operator+
void slice(unsigned int first, unsigned int last) {
// ...
auto it = this->begin() + first; // <--------
// ...
}
};
Maybe I am missing something but how (Iterator, ptrdiff_t) and (int, unsigned int) are ambiguous?
I haven't compiled this, but the problem appears to be that operator bool(); it provides an implicit conversion to bool, which is, in turn, convertible to int. Iterators in general don't provide their own validation, so this is unusual. If you need it, mark it explicit. That will prevent the implicit conversion.
Hi everyone,
I'm having problems implementing my own List with iterator for the project at Univeristy. What should I do for correct iterating over loop? Could somebody help me? Sory for my English if is incorrect.
#ifndef __List__
#define __List__
template <class type>
class List
{
public:
struct Node
{
type value;
Node* next;
};
Node* root;
class iterator
{
public:
typedef iterator self_type;
typedef Node& reference;
typedef Node* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
iterator(pointer ptr) : ptr_(ptr) { }
self_type operator++() { self_type i = *this->ptr_->next; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
reference operator*() { return ptr_; }
type operator->() { return ptr->value; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
class const_iterator
{
public:
typedef const_iterator self_type;
typedef type value_type;
typedef Node& reference;
typedef Node* pointer;
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
const_iterator(pointer ptr) : ptr_(ptr) { }
self_type operator++() { self_type i = *this->ptr_->next; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
const reference operator*() { return *ptr_; }
const type operator->() { return ptr->value; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
List();
List(std::initializer_list<type> vals);
~List();
iterator begin()
{
return iterator(root);
}
iterator end()
{
return iterator(nullptr);
}
const_iterator begin() const
{
return const_iterator(root);
}
const_iterator end() const
{
return const_iterator(nullptr);
}
Node* last();
void push_back(type obj);
};
template <class type>
List<type>::List()
{
root = nullptr;
}
template <class type>
List<type>::List(std::initializer_list<type> vals)
{
root = nullptr;
for (auto& elem : vals)
push_back(elem);
}
template <class type>
List<type>::~List()
{
}
template <class type>
typename List<type>::Node* List<type>::last()
{
Node* tmp = root;
while (tmp->next != nullptr)
tmp = tmp->next;
return tmp;
}
template <class type>
void List<type>::push_back(type obj)
{
Node* tmp = new Node;
tmp->value = obj;
tmp->next = nullptr;
if (root == nullptr)
root = tmp;
else
{
Node* l = last();
l->next = tmp;
}
}
#endif
I would like to iterate over my List like the first loop or even the second.
int main()
{
List<Product*> ProductBase{ new Product("Lubella Spaghetti 500 g", 10.0, 3.1, 0.23, 1), new Product("Nescafé Gold Blend 200 g", 20.0, 1.2, 0.23, 1) };
for (auto i = ProductBase.begin(); i != ProductBase.end(); ++i)
i->display_product();
for (auto elem : ProductBase)
elem->display_product();
system("PAUSE");
}
In the operator++ of the iterator and const_iterator you need to add
_ptr = ptr_->next
and I would rather not implement
self_type operator++(int junk)
in the iterator class. List iterators typically can only advance one step forward.
Also, in the const_iterator, make sure you only return const pointers, so that the compiler will issue an error if the caller tries to use the const_iterator to mutate the list.
Following on from this question: std::list implementation & pointer arithemetic.
I want to implement a list iterator that is interchangeable with other common containers types and their respective iterators, so I want to use operators such as: --, ++, * and be able to declare iterators as normal, so: list::iterator iter = list.begin();
The --, ++ operators now work as they should, but I ran up against the problem of de-referencing the iterator, as structs can't return a value: T iterator::operator*()
template <class T>
struct element {
element<T> *prev = NULL;
element<T> *next = NULL;
T data;
};
template <typename T>
class list {
public:
list::list();
element<T>* current;
struct iterator{
element<T>* iterator::operator++(){
this = *this->next; ..whatever it works
}
element<T>* iterator::operator--()
T iterator::operator*()
}
};
the iterators could look something like this:
(declared inside the list template)
struct iterator;
struct const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T>
{
const_iterator() = default;
T operator*() { return itm->data; }
const T* operator->() { return &(itm->data); }
const_iterator operator++() { itm = itm->next; return *this; }
const_iterator operator--() { itm = itm->prev; return *this; }
const_iterator operator++(int) { const_iterator ret=*this; itm = itm->next; return ret; }
const_iterator operator--(int) { const_iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(const_iterator oth) const { return itm==oth.itm; }
bool operator!=(const_iterator oth) const { return itm!=oth.itm; }
private:
element<T>* itm = nullptr;
const_iterator(element<T>* i) : itm(i) {}
friend
class list;
friend
struct iterator;
};
struct iterator : public std::iterator<std::bidirectional_iterator_tag, T>
{
iterator() = default;
T& operator*() { return itm->data; }
T* operator->() { return &(itm->data); }
iterator operator++() { itm = itm->next; return *this; }
iterator operator--() { itm = itm->prev; return *this; }
iterator operator++(int) { iterator ret=*this; itm = itm->next; return ret; }
iterator operator--(int) { iterator ret=*this; itm = itm->prev; return ret; }
bool operator==(iterator oth) const { return itm==oth.itm; }
bool operator!=(iterator oth) const { return itm!=oth.itm; }
operator const_iterator() { return {itm}; }
private:
element<T>* itm = nullptr;
iterator(element<T>* i) : itm(i) {}
friend
class list;
};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
this needs
#include <iterator>
to compile