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
Related
Let's suppose I have two classes, the first:
class IntMatrix::iterator {
private:
const IntMatrix *int_matrix;
int index;
iterator(const IntMatrix *int_matrix, int index);
friend class IntMatrix;
public:
int &operator*() const;
iterator &operator++();
iterator operator++(int);
bool operator==(const iterator &it) const;
bool operator!=(const iterator &it) const;
iterator(const iterator &) = default;
iterator &operator=(const iterator &) = default;
~iterator() = default;
};
and the second is:
class IntMatrix::const_iterator {
private:
const IntMatrix *int_matrix;
int index;
const_iterator(const IntMatrix *int_matrix, int index);
friend class IntMatrix;
public:
const int &operator*() const;
const_iterator &operator++();
const_iterator operator++(int);
bool operator==(const const_iterator &it) const;
bool operator!=(const const_iterator &it) const;
const_iterator(const const_iterator &) = default;
const_iterator &operator=(const const_iterator &) = default;
~const_iterator() = default;
};
How may I prevent code duplication here, since the implementation is 99% the same?
How about generics may it help here or inheritance?
An example of how they are implemented:
int &IntMatrix::iterator::operator*() const {
return int_matrix->data[index];
}
const int &IntMatrix::const_iterator::operator*() const {
return int_matrix->data[index];
}
Plus, I want In main to allow something like:
IntMatrix::iterator it;
Update:
I'm trying to implement the given solution on a Generic class called Matrix in the following way: (Note the code shown is all written as public in my class)
template<typename T>
class iterator_impl;
template<typename T>
iterator_impl<T> begin(){
return iterator(this, 0);
}
template<typename T>
iterator_impl<T> end(){
return iterator(this, size());
}
template<typename T>
iterator_impl<const T> begin() const
{
return const_iterator(this, 0);
}
template<typename T>
iterator_impl<const T> end() const
{
return const_iterator(this, size());
}
template<typename T>
class iterator_impl{
private:
const Matrix<T> *matrix;
int index;
friend class Matrix<T>;
public:
iterator_impl(const iterator_impl &) = default;
iterator_impl &operator=(const iterator_impl &) = default;
~iterator_impl() = default;
iterator_impl(const Matrix<T> *int_matrix, int index)
: matrix(int_matrix), index(index) {}
iterator_impl &operator++()
{
++index;
return *this;
}
iterator_impl operator++(int)
{
iterator_impl result = *this;
++*this;
return result;
}
bool operator==(const iterator_impl &it) const
{
return index == it.index;
}
bool operator!=(const iterator_impl &it) const
{
return !(*this == it);
}
T &operator*() const {
if (index < 0 || index > matrix->size() - 1) {
throw Matrix<T>::AccessIllegalElement();
}
return matrix->data[index];
}
};
template<typename T>
using iterator = iterator_impl<T>;
template<typename T>
using const_iterator = iterator_impl<const T>;
and I'm getting some errors like:
invalid use of 'this' outside of a non-static member function
return iterator(this, 0);
One way is to make the implementation into a class template and then to make aliases for the const and non-const instantiations.
Plus, I want In main to allow something like:
IntMatrix::iterator it;
You then need to add a default constructor.
Example:
#include <cstddef>
#include <type_traits>
// in the .hpp file:
class IntMatrix {
private:
int data[10]; // just an example
size_t size = 10; // just an example
template<typename T>
class iterator_impl;
public:
// two typedefs using the template:
using iterator = iterator_impl<int>;
using const_iterator = iterator_impl<const int>;
const_iterator cbegin() const;
const_iterator cend() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
};
// still in the .hpp file:
template<typename T>
class IntMatrix::iterator_impl {
public:
using matrix_type =
std::conditional_t<
std::is_const_v<T>,
const IntMatrix,
IntMatrix
>;
private:
matrix_type* int_matrix;
size_t index;
friend IntMatrix;
iterator_impl(matrix_type* im, size_t idx) :
int_matrix(im), index(idx)
{}
public:
iterator_impl() = default; // default constructor
//iterator_impl(const iterator_impl&) = default; // not needed
//iterator_impl &operator=(const iterator_impl &) = default; // not needed
//~iterator_impl() = default; // not needed
iterator_impl &operator++() {
++index;
return *this;
}
iterator_impl operator++(int) {
iterator_impl old(*this);
++index;
return old;
}
bool operator!=(const iterator_impl &it) const {
return index != it.index || int_matrix != it.int_matrix;
}
bool operator==(const iterator_impl &it) const {
return !(*this != it);
}
T& operator*() const {
return int_matrix->data[index];
}
};
// in the .cpp file:
IntMatrix::const_iterator IntMatrix::cbegin() const { return {this, 0}; }
IntMatrix::const_iterator IntMatrix::cend() const { return {this, size}; }
IntMatrix::const_iterator IntMatrix::begin() const { return cbegin(); }
IntMatrix::const_iterator IntMatrix::end() const { return cend(); }
IntMatrix::iterator IntMatrix::begin() { return {this, 0}; }
IntMatrix::iterator IntMatrix::end() { return {this, size}; }
Demo
Edit: If Matrix is a class template itself, you need to change the iterator slightly.
#include <cstddef>
#include <type_traits>
// in the .hpp file:
template<typename T>
class Matrix {
private:
T data[10]; // just an example
size_t size = 10; // just an example
template<typename I>
class iterator_impl;
public:
// two typedefs using the template:
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
auto cbegin() const;
auto cend() const;
auto begin() const;
auto end() const;
auto begin();
auto end();
};
// still in the .hpp file:
template<typename T>
template<typename I>
class Matrix<T>::iterator_impl {
public:
using value_type = std::remove_const_t<I>;
using matrix_type =
std::conditional_t<
std::is_const_v<I>,
const Matrix<value_type>,
Matrix<value_type>
>;
private:
matrix_type* matrix;
size_t index;
friend Matrix;
iterator_impl(matrix_type* im, size_t idx) :
matrix(im), index(idx)
{}
public:
iterator_impl() = default; // default constructor
iterator_impl& operator++() {
++index;
return *this;
}
iterator_impl operator++(int) {
iterator_impl old(*this);
++index;
return old;
}
bool operator!=(const iterator_impl &it) const {
return index != it.index || matrix != it.matrix;
}
bool operator==(const iterator_impl &it) const {
return !(*this != it);
}
I& operator*() const {
return matrix->data[index];
}
};
// still in the .hpp file
template<typename T> auto Matrix<T>::cbegin() const { return const_iterator{this, 0}; }
template<typename T> auto Matrix<T>::cend() const { return const_iterator{this, size}; }
template<typename T> auto Matrix<T>::begin() const { return cbegin(); }
template<typename T> auto Matrix<T>::end() const { return cend(); }
template<typename T> auto Matrix<T>::begin() { return iterator{this, 0}; }
template<typename T> auto Matrix<T>::end() { return iterator{this, size}; }
Demo
I’m trying to implement my stl-like container, which in fact will be an incomplete version of a map.
Faced a problem at the time of implementation of the erase method, I do not understand how to delete a pair of <key, value>.
I am stuck, so I ask for help. Can someone please guide me to the solution? Here is the code.
P.S.: Im only starting to learn C++;
void erace(const key_type& Key)
{
int n = 1;
for (iterator i = begin(); i != end(); ++i, n++)
{
if (i->first == Key)
{
//TO DO.
}
}
}
Whole code:
template < typename Key, typename T, typename Compare = std::less<Key>, typename Allocator = std::allocator< std::pair<const Key, T> > >
class map
{
public:
class miterator
{
public:
typedef miterator self_type;
typedef std::pair<const Key, T> value_type;
typedef std::pair<const Key, T>& reference;
typedef std::pair<const Key, T>* pointer;
typedef std::bidirectional_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
miterator(pointer ptr) : ptr_(ptr) { };
miterator() {}
self_type operator=(const self_type& other) { ptr_ = other.ptr_; return *this; }
self_type operator++() { self_type i = *this; ptr_++; return i; }
self_type operator--() { self_type i = *this; ptr_--; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
self_type operator--(int junk) { ptr_--; return *this; }
reference operator*() { return *ptr_; }
pointer operator->() { return ptr_; }
pointer operator&() { return ptr_; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
class mconst_iterator
{
public:
typedef mconst_iterator self_type;
typedef std::pair<const Key, T> value_type;
typedef std::pair<const Key, T>& reference;
typedef std::pair<const Key, T>* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
mconst_iterator(pointer ptr) : ptr_(ptr) { };
mconst_iterator() {}
self_type operator=(const self_type& other) { ptr_ = other.ptr_; return *this; }
self_type operator++() { self_type i = *this; ptr_++; return i; }
self_type operator--() { self_type i = *this; ptr_--; return i; }
self_type operator++(int junk) { ptr_++; return *this; }
self_type operator--(int junk) { ptr_--; return *this; }
reference operator*() { return *ptr_; }
pointer operator->() { return ptr_; }
pointer operator&() { return ptr_; }
bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }
pointer ptr_;
};
typedef map<Key, T, Compare, Allocator> mymap;
typedef Key key_type;
typedef T mapped_type;
typedef std::pair<const Key, T> value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef Compare key_compare;
typedef Allocator allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef miterator iterator;
typedef mconst_iterator const_iterator;
typedef std::reverse_iterator<miterator> reverse_iterator;
typedef std::reverse_iterator<mconst_iterator> const_reverse_iterator;
map()
: size(0), capacity(20), data(Allocator().allocate(20))
{
}
map(const mymap& _Rhs)
: size(_Rhs.size), capacity(_Rhs.size + 20), data(Allocator().allocate(_Rhs.size))
{
int count = 0;
for (iterator i = &_Rhs.data[0]; i != &_Rhs.data[_Rhs.size]; ++i, ++count)
{
Allocator().construct(&data[count], *i);
}
}
~map()
{
if (!empty())
{
Allocator().deallocate(data, capacity);
}
}
mymap& insert(const value_type& pair)
{
if (!is_present(pair))
{
if (++size >= capacity)
{
reserve(capacity * 2);
}
Allocator().construct(&data[size - 1], pair);
return *this;
}
}
bool is_present(const value_type& pair)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == pair.first)
{
return true;
}
return false;
}
}
bool has_key(const key_type& _Key)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == _Key)
{
return true;
}
}
return false;
}
mapped_type& operator[](const key_type& _Key)
{
if (has_key(_Key))
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == _Key)
{
return i->second;
}
}
}
size_type op = size;
insert(value_type(_Key, mapped_type()));
return data[op].second;
}
mymap& reserve(size_type _Capacity)
{
int count = 0;
if (_Capacity < capacity)
{
return *this;
}
pointer buf = Allocator().allocate(_Capacity);
for (iterator i = begin(); i != end(); ++i, ++count)
{
Allocator().construct(&buf[count], *i);
}
std::swap(data, buf);
Allocator().deallocate(buf, capacity);
capacity = _Capacity;
return *this;
}
void erace(const key_type& Key)
{
int n = 1;
for (iterator i = begin(); i != end(); ++i, n++)
{
if (i->first == Key)
{
//TO DO
}
}
}
size_type get_size() const { return get_size; }
bool empty() const
{
return size == 0;
}
iterator clear()
{
~map();
}
iterator begin()
{
return &data[0];
}
iterator end()
{
return &data[size];
}
reverse_iterator rbegin()
{
return &data[0];
}
reverse_iterator rend()
{
return &data[size];
}
const_iterator cbegin() const
{
return &data[0];
}
const_iterator cend() const
{
return &data[size];
}
const_reverse_iterator rbegin() const
{
return &data[0];
}
const_reverse_iterator rend() const
{
return &data[size];
}
iterator find(const key_type& Key)
{
for (iterator i = begin(); i != end(); ++i)
{
if (i->first == Key)
{
return i;
}
}
iterator res = end();
return res;
}
private:
pointer data;
size_type size, capacity;
};
Since you represent the map as an array of pairs, this is the same as erasing an element from an array.
Since the order isn't important, you can swap the last element with the one you're removing, then destroy the removed element and adjust the size.
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.
I'm working on a file, Deque.hpp, which uses an iterator class and Nodes to make a deque, but I'm getting the error:
"Error C1004 unexpected end-of-file found "
I can't seem to find what's causing this. Here's my code.
#ifndef DEQUE_H
#define DEQUE_H
#include <iostream>
#include <new>
#include <cstdlib>
#include <algorithm>
//
//
//
template <typename T>
class Deque
{
public:
Deque();
Deque(const Deque & rhs);
~Deque();
Deque & operator= (const Deque & rhs);
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail };
Deque & operator= (Deque && rhs);
T & Deque<T>::operator[](int n);
Iterator begin();
const_iterator begin() const;
Iterator end();
const_iterator end() const;
int size() const;
bool isEmpty() const;
void clear();
T & left();
const T & left() const;
T & right();
const T & right() const;
void pushLeft(const T & x);
void pushLeft(T && x);
void pushRight(const T & x);
void pushRight(T && x);
T & popLeft();
T & popRight();
bool Deque<T>::contains(const T&);
struct Node
{
T data;
Node *prev;
Node *next;
Node(const T & d = T{}, Node * p = NULL, Node * n = NULL) :
data{ d }, prev{ p }, next{ n } {}
Node(T && d, Node * p = NULL, Node * n = NULL)
: data{ std::move(d) }, prev{ p }, next{ n } {}
};
class const_iterator
{
public:
const_iterator() : current{ NULL } { }
const T & operator* () const;
const_iterator & operator++ ();
const_iterator & operator-- (); //!
const_iterator operator++ (int);
const_iterator operator-- (int); //!
bool operator== (const const_iterator & rhs) const;
bool operator!= (const const_iterator & rhs) const;
protected:
Node *current;
T & retrieve() const;
const_iterator(Node *p) : current{ p } { }
friend class Deque<T>;
};
class Iterator : public const_iterator
{
public:
Iterator();
T & operator* ();
const T & operator* () const;
Iterator & operator++ ();
Iterator & operator-- (); //!
Iterator operator++ (int);
Iterator operator-- (int); //!
protected:
Iterator(Node *p) : const_iterator{ p } { }
friend class Deque<T>;
};
private:
// Insert x before itr.
Iterator insert(Iterator itr, const T & x);
// Insert x before itr.
Iterator insert(Iterator itr, T && x);
// Erase item at itr.
Iterator erase(Iterator itr);
Iterator erase(Iterator from, Iterator to);
int theSize;
Node *head;
Node *tail;
void init();
};
template<typename T>
inline const T & Deque<T>::const_iterator::operator*() const
{
return retrieve();
}
template<typename T>
inline const_iterator & Deque<T>::const_iterator::operator++()
{
current = current->next;
return *this;
}
template<typename T>
inline const_iterator & Deque<T>::const_iterator::operator--()
{
current = current->prev;
return *this;
}
template<typename T>
inline const_iterator Deque<T>::const_iterator::operator++(int)
{
const_iterator old = *this;
++(*this);
return old;
}
template<typename T>
inline const_iterator Deque<T>::const_iterator::operator--(int)
{
const_iterator old = *this;
--(*this);
return old;
}
template<typename T>
inline bool Deque<T>::const_iterator::operator==(const const_iterator & rhs) const
{
return current == rhs.current;
}
template<typename T>
inline bool Deque<T>::const_iterator::operator!=(const const_iterator & rhs) const
{
return !(*this == rhs);
}
template<typename T>
inline T & Deque<T>::const_iterator::retrieve() const
{
return current->data;
}
template<typename T>
inline Deque<T>::Iterator::Iterator()
{
}
template<typename T>
inline T & Deque<T>::Iterator::operator*()
{
return const_iterator::retrieve();
}
template<typename T>
inline const T & Deque<T>::Iterator::operator*() const
{
return const_iterator::operator*();
}
template<typename T>
inline Iterator & Deque<T>::Iterator::operator++()
{
this->current = this->current->next;
return *this;
}
template<typename T>
inline Iterator & Deque<T>::Iterator::operator--()
{
this->current = this->current->prev;
return *this;
}
template<typename T>
inline Iterator Deque<T>::Iterator::operator++(int)
{
Iterator old = *this;
++(*this);
return old;
}
template<typename T>
inline Iterator Deque<T>::Iterator::operator--(int)
{
Iterator old = *this;
--(*this);
return old;
}
template<typename T>
inline Deque<T>::Deque()
{
init();
}
template<typename T>
inline Deque<T>::~Deque()
{
clear();
delete head;
delete tail;
}
template<typename T>
inline Deque & Deque<T>::operator=(const Deque & rhs)
{
if (this == &rhs)
return *this;
clear();
for (const_iterator itr = rhs.begin(); itr != rhs.end(); ++itr)
pushRight(*itr)
return *this;
}
template<typename T>
inline Deque<T>::Deque(Deque && rhs)
{
rhs.theSize = 0;
rhs.head = NULL;
rhs.tail = NULL;
}
template<typename T>
inline Deque & Deque<T>::operator=(Deque && rhs)
{
std::swap(theSize, rhs.theSize);
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
return *this;
}
template<typename T>
inline T & Deque<T>::operator[](int n)
{
Iterator itr = begin();
for (int i = 0; i < n; i++)
{
itr.current = itr.current->next;
}
return itr.current->data;
}
template<typename T>
inline Iterator Deque<T>::begin()
{
return{ head->next };
}
template<typename T>
inline const_iterator Deque<T>::begin() const
{
return{ head->next };
}
template<typename T>
inline Iterator Deque<T>::end()
{
return{ tail->prev }; //changed to -> prev
}
template<typename T>
inline const_iterator Deque<T>::end() const
{
return{ tail->prev };
}
template<typename T>
inline int Deque<T>::size() const
{
return theSize;
}
template<typename T>
inline bool Deque<T>::isEmpty() const
{
return size() == 0;
}
template<typename T>
inline void Deque<T>::clear()
{
while (!isEmpty())
popLeft();
}
template<typename T>
inline T & Deque<T>::left()
{
return *begin();
}
template<typename T>
inline const T & Deque<T>::left() const
{
return *begin();
}
template<typename T>
inline T & Deque<T>::right()
{
return *end(); // deleted "--*end"
}
template<typename T>
inline const T & Deque<T>::right() const
{
return *end();
}
template<typename T>
inline void Deque<T>::pushLeft(const T & x)
{
insert(begin(), x);
}
template<typename T>
inline void Deque<T>::pushLeft(T && x)
{
insert(begin(), std::move(x)); // changed std::move(x)) to x
}
template<typename T>
inline void Deque<T>::pushRight(const T & x)
{
insert(end(), x);
}
template<typename T>
inline void Deque<T>::pushRight(T && x)
{
insert(end(), std::move(x));
}
template<typename T>
inline T & Deque<T>::popLeft()
{
return *begin(); erase(begin());
}
template<typename T>
inline T & Deque<T>::popRight()
{
return *end(); erase(end()); // changed --end to end
}
template<typename T>
inline bool Deque<T>::contains(const T &)
{
// stuff here
}
template<typename T>
inline Iterator Deque<T>::insert(Iterator itr, const T & x)
{
Node *p = itr.current;
theSize++;
return{ p->prev = p->prev->next = new Node{ x, p->prev, p } };
}
template<typename T>
inline Iterator Deque<T>::insert(Iterator itr, T && x)
{
Node *p = itr.current;
theSize++;
return{ p->prev = p->prev->next = new Node{ std::move(x), p->prev, p } };
}
template<typename T>
inline Iterator Deque<T>::erase(Iterator itr)
{
Node *p = itr.current;
Iterator retVal{ p->next };
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
theSize--;
return retVal;
}
template<typename T>
inline Iterator Deque<T>::erase(Iterator from, Iterator to)
{
for (Iterator itr = from; itr != to; )
itr = erase(itr);
return to;
}
template<typename T>
inline void Deque<T>::init()
{
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->prev = head;
}
template<typename T>
inline Deque<T>::Deque(const Deque & rhs)
{
init();
*this = rhs;
}
#endif
The first error to fix is the one identified by Algirdas Preidžius: your constructor has an initialization list but no body.
You should replace
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail };
by
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail } {};
Then you'll have a lot of other errors to fix. Good luck !
My advice when coding: write your code incrementaly, build and test regularly. You shouldn't have so much errors to fix at once !
By the way, any reason to not use std::deque ?
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.