I'm trying to implement a template class which is almost the same as the STL implementation of list.
Now i'm working on the range overload of the std::insert() function. The prototype is :
template <class InputIterator> iterator insert (const_iterator position, InputIterator first, InputIterator last);
The problem is : i can't get the first and last iterators to do anything. Whenever i'm trying to dereference them (*first), i'm getting an "illegal indirection" error at compilation. The only operation i can perform is first++, and when i'm trying it with a std::vector<int>::iterator, first is obviously returning the next element.
Here is the most important part of my class :
template <class T>
class List {
public:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef std::size_t size_type;
/* Structures / Classes */
struct Node {
Node* previous;
Node* next;
Node() : previous(this), next(this) {};
Node(Node* previous) : previous(previous), next(this) {};
};
struct DataNode : public Node {
value_type data;
DataNode(const_reference data) : Node(), data(data) {};
virtual ~DataNode() {};
};
class ListIterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
{
friend class List;
private:
Node* node;
public:
ListIterator() : node(0) {};
ListIterator(Node* ptr) : node(ptr) {};
ListIterator(const ListIterator& other) : node(other.node) {};
virtual ~ListIterator() {};
ListIterator& operator++() { node = node->next; return *this; };
ListIterator operator++(int) {
ListIterator tmp(*this);
operator++();
return tmp;
};
ListIterator& operator--() { node = node->previous; return *this; };
ListIterator operator--(int) {
ListIterator tmp(*this);
operator--();
return tmp;
};
bool operator==(const ListIterator& other) { return node == other.node; };
bool operator!=(const ListIterator& other) { return node != other.node; };
ListIterator& operator=(const ListIterator& other) {
if (this != &other) this->node = other.node;
return *this;
}
value_type& operator*() { return reinterpret_cast<DataNode*>(node)->data; }
};
class ConstListIterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> {
/* same with const ... */
};
/* More typedefs... */
typedef ListIterator iterator;
typedef ConstListIterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
protected:
/* Class members */
Node* root; // at the end
size_type elementCount;
public:
/* functions... */
iterator insert(const_iterator position, const value_type& val);
iterator insert(const_iterator position, size_type n, const value_type& val);
template<class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, value_type&& val);
iterator insert(const_iterator position, std::initializer_list<value_type> il);
/* more functions... */
};
And the declaration of the function :
template <class T>
template <class InputIterator>
inline typename List<T>::iterator List<T>::insert(const_iterator position, InputIterator first, InputIterator last)
{
/* i don't know how to deal with the InputIterator */
value_type a(*first); // Illegal indirection
iterator it(first); // not working
}
Any help is welcome
Related
I am trying to write a linked list set compatible with the standard-library and am getting an error I cannot understand.
#include <iterator>
#include <cstddef>
template <typename T>
class SetList{
struct ListNode{
T data;
ListNode * next;
ListNode(T newData, ListNode* newNext): data(newData), next(newNext){}
ListNode(ListNode& l): data(l.data), next(l.next){}
ListNode& operator=(ListNode & l){
data = l.data;
next = l.next;
return this;
}
};
public:
ListNode* head;
typedef T value_type;
class iterator;
typedef iterator iterator_type;
class const_iterator;
SetList(): head(nullptr){}
~SetList(){
//delete entire list
}
SetList(SetList<T>& sl): head(sl.head){}
iterator begin(){
return iterator(head);
}
iterator end(){
return iterator(nullptr);
}
class iterator
{
//traits
friend class SetList;
friend class const_iterator;
typedef std::forward_iterator_tag iterator_category;
typedef iterator self_type;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef int difference_type;
private:
ListNode* ihead;
public:
iterator(ListNode* newHead = nullptr): ihead(newHead){}
iterator(const iterator& it): ihead(it.ihead){}
iterator& operator=(iterator& it){ihead = it.ihead; return *this;}
reference operator*(){return ihead->data;}
pointer operator->() const{ return ihead;}
iterator& operator++(){ihead = ihead->next; return *this;}
bool operator!=(const iterator& it) const{
return ihead != it.ihead;
}
bool operator==(const iterator& it) const{
return ihead == it.ihead;
}
};
class const_iterator
{
//traits
friend class SetList;
friend class iterator;
typedef std::forward_iterator_tag iterator_category;
typedef const_iterator self_type;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef int difference_type;
private:
const ListNode* ihead;
public:
const_iterator(const ListNode* newHead = nullptr): ihead(newHead){}
const_iterator(const iterator& it): ihead(it.ihead){}
const_iterator(const const_iterator& it): ihead(it.ihead){}
const_iterator& operator=(const const_iterator& it){ihead = it.ihead; return *this;}
const_iterator& operator=(const iterator& it){ihead = it.ihead; return *this;}
reference operator*()const {return ihead->data;}
pointer operator->() const{ return ihead;}
const_iterator& operator++(){ihead = ihead->next; return *this;}
bool operator!=(const const_iterator& it) const{
return ihead != it.ihead;
}
bool operator==(const const_iterator& it) const{
return ihead == it.ihead;
}
};
public:
void insert(T newData){
if(head){
ListNode* cur = new ListNode(newData, head);
head = cur;
}else{
head = new ListNode(newData, nullptr);
}
}
SetList& operator=(SetList& sl){
}
};
The error message is:
This appears to be saying that it cannot find certain types in iterator_traits, but I do not understand how what my code does has any bearing on what types are defined there.
You declared all types in iterator as private typedefs so they are unavailable from iterator_traits. If you change:
friend class SetList;
friend class const_iterator;
typedef std::forward_iterator_tag iterator_category;
typedef iterator self_type;
typedef T value_type;
to:
friend class SetList;
friend class const_iterator;
public:
typedef std::forward_iterator_tag iterator_category;
typedef iterator self_type;
typedef T value_type;
//...
code compiles. Compiler errors tell that you have used std::copy algo with SetList, below is the code which works fine after making typedefs in iterator as public:
SetList<int> sl;
sl.insert(1);
std::vector<int> v;
std::copy(sl.begin(), sl.end(), std::back_inserter(v));
for (int i : v)
std::cout << i << std::endl;
I have the following classes and I am trying to overload the operator* from the inner class iterator
#ifndef __LISTMAP_H__
#define __LISTMAP_H__
#include "xless.h"
#include "xpair.h"
template <typename Key, typename Value, class Less=xless<Key>>
class listmap {
public:
using key_type = Key;
using mapped_type = Value;
using value_type = xpair<const key_type, mapped_type>;
private:
Less less;
struct node;
struct link {
node* next{};
node* prev{};
link (node* next, node* prev): next(next), prev(prev){}
};
struct node: link {
value_type value{};
node (node* next, node* prev, const value_type&);
};
node* anchor() { return static_cast<node*> (&anchor_); }
link anchor_ {anchor(), anchor()};
public:
class iterator;
listmap(){};
listmap (const listmap&) = default;
listmap& operator= (const listmap&) = default;
~listmap();
iterator insert (const value_type&);
iterator find (const key_type&);
iterator erase (iterator position);
iterator begin() { return anchor()->next; }
iterator end() { return anchor(); }
bool empty() const { return begin() == end(); }
};
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
private:
friend class listmap<Key,Value>;
listmap<Key,Value,Less>::node* where {nullptr};
iterator (node* where): where(where){};
public:
iterator(){}
value_type& operator*();
value_type* operator->();
iterator& operator++(); //++itor
iterator& operator--(); //--itor
void erase();
bool operator== (const iterator&) const;
bool operator!= (const iterator&) const;
};
template <typename Key, typename Value, class Less>
value_type& listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator*()
{
return where->value;
}
#include "listmap.tcc"
#endif
The problem is that value_type is a public member from the class listmap and it's not static, so I don't know how to complete the declaration of operator*(). I wouldn't like to fix the bug by changing the structure of the code. Ex: making
using value_type = xpair<const key_type, mapped_type>;
Global. I am just wondering if there is some other trick I can use to access value_type.
....edit: I have no idea how the inner class recognizes value_type
It's barely the same as for iterator, you just have to add typename keyword
typename listmap<Key,Value,Less>::value_type
staticness doesn't matter for a type.
The alias1 inside iterator
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
...
using value_type = typename listmap<Key,Value,Less>::value_type;
};
allows you to write the definition more succinctly using auto suffix type:
template <typename Key, typename Value, class Less>
auto listmap<Key,Value,Less>::iterator::operator*() -> value_type&
{
return where->value;
}
Careful: inner iterator class is not template, only listmap is:
listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator
// ~~~~~~~~~~~~~~~~ remove this
1 Btw don't forget the others.
In my everlasting effort to implement a link list I created a class-template representing the container (CursorList) and I have a seperate class-template that is supposed to be my iterator (CursorIterator).
In my CursorList I use a struct Node to represent elements of the list. I want to share this struct with my CursorIterator-Class (the iterator is pointing towards a Node). However this doesn't work as I want it to, I can't really get both classes to know the structures of Node.
CursorList.h
#ifndef CURSORLIST_H
#define CURSORLIST_H
#include "CursorIterator.h"
template <class T> class CursorList {
public:
CursorList() {}
typedef T value_type;
typedef CursorIterator<T> iterator;
bool empty() const;
int size() const;
T& front() const;
void push_front(const T& item);
void pop_front();
iterator begin() const;
iterator end() const;
iterator insert(iterator itr, const T& value);
iterator erase(iterator start, iterator stop);
iterator erase(iterator itr);
struct Node {
Node(const T& n_data, Node* n_prev, Node* n_next): data(n_data), prev(n_prev), next(n_next) {}
T data;
Node* prev;
Node* next;
};
private:
Node* m_head;
};
#endif //CURSORLIST_H
CursorIterator.h
#ifndef CURSORITERATOR_H
#define CURSORITERATOR_H
template <class T> class CursorIterator {
private:
typedef CursorIterator<T> iterator;
Node* m_rep;
public:
CursorIterator() {}
CursorIterator(Node* n): m_rep(n) {}
T& operator *();
iterator& operator = (const iterator& rhs);
bool operator != (const iterator& rhs) const;
bool operator == (const iterator& rhs) const;
iterator& operator ++();
iterator operator ++(int);
};
#endif //CURSORITERATOR_H
I'm implementing STL containers, for example, vector. What confused me is the implementation of iterators.
If I want to implement all iterator categories: input_iterator, output_iterator, forward_iterator, bidirectional_iterator and random_access_iterator.
How do I manage their inheritance relationships?
I've read How to implement an STL-style iterator and avoid common pitfalls?-Mooing Duck's Answer
This is his example symbolic:
iterator {
iterator(const iterator&);
~iterator();
iterator& operator=(const iterator&);
iterator& operator++(); //prefix increment
reference operator*() const;
friend void swap(iterator& lhs, iterator& rhs); //C++11 I think
};
input_iterator : public virtual iterator {
iterator operator++(int); //postfix increment
value_type operator*() const;
pointer operator->() const;
friend bool operator==(const iterator&, const iterator&);
friend bool operator!=(const iterator&, const iterator&);
};
//once an input iterator has been dereferenced, it is
//undefined to dereference one before that.
output_iterator : public virtual iterator {
reference operator*() const;
iterator operator++(int); //postfix increment
};
//dereferences may only be on the left side of an assignment
//once an input iterator has been dereferenced, it is
//undefined to dereference one before that.
forward_iterator : input_iterator, output_iterator {
forward_iterator();
};
//multiple passes allowed
bidirectional_iterator : forward_iterator {
iterator& operator--(); //prefix increment
iterator operator--(int); //postfix decrement
};
random_access_iterator : bidirectional_iterator {
friend bool operator<(const iterator&, const iterator&);
friend bool operator>(const iterator&, const iterator&);
friend bool operator<=(const iterator&, const iterator&);
friend bool operator>=(const iterator&, const iterator&);
iterator& operator+=(size_type);
friend iterator operator+(const iterator&, size_type);
friend iterator operator+(size_type, const iterator&);
iterator& operator-=(size_type);
friend iterator operator-(const iterator&, size_type);
friend difference_type operator-(iterator, iterator);
reference operator[](size_type) const;
};
But I found a problem:
If I have an instance a from class random_access_iterator, I use the code random_access_iterator b = a + 1. This will cause compile error. Because a + 1's class is base iterator, not random_access_iterator.
So I don't think this is a reasonable solution.
Do I misunderstand it? Or please tell me an elegant and efficient way to implement it.
Thanks
I think you should use CRTP (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
Like this:
template <typename T, typename ItT>
struct iiterator_t {
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef ItT iterator_type;
virtual iterator_type& operator=(const iterator_type&) = 0;
virtual iterator_type& operator++() = 0;
virtual reference operator*() const = 0;
};
template <typename T, typename ItT>
struct iterator_impl_t : virtual public iiterator_t<T, ItT>{
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef ItT iterator_type;
iterator_type& operator=(const iterator_type &rhs)
{
p = static_cast<const iterator_impl_t&>(rhs).p;
return dynamic_cast<iterator_type&>(*this);
}
iterator_type& operator++()
{
++p;
return dynamic_cast<iterator_type&>(*this);
}
reference operator*() const
{
return *p;
}
private:
pointer p;
};
template <typename T, typename ItT>
struct iinput_iterator_t : public virtual iiterator_t<T, ItT> {
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef ItT iterator_type;
virtual iterator_type operator++(int) = 0;
};
template <typename T, typename ItT>
struct input_iterator_impl_t :
public virtual iinput_iterator_t<T, ItT>,
public virtual iterator_impl_t<T, ItT>
{
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef ItT iterator_type;
iterator_type operator++(int)
{
iterator_type result(dynamic_cast<const iterator_type &>(*this));
++dynamic_cast<iterator_impl_t<T, ItT> &>(*this);
return result;
}
};
template <typename T>
struct iterator :
public virtual iterator_impl_t<T, iterator<T> >
{
};
template <typename T>
struct input_iterator :
public virtual input_iterator_impl_t<T, input_iterator<T>>
{
};
int main(int , char** )
{
iterator<int> i;
iterator<int> i2 = ++i;
input_iterator<int> inpi;
input_iterator<int> inpi2 = inpi++;
return 0;
}
Iterator categories are nothing but empty structs that act as tags.
Once finished implementing the features of your iterator class, you add its information (like which category it belongs to) into a std::iterator_traits specialization. Here's an example:
namespace std {
template <typename T>
struct iterator_traits<my_iota_iterator<T>> {
using value_type = T;
using difference_type = T;
using pointer = T const*;
using reference = T const&;
using iterator_category = std::random_access_iterator_tag; // !!
} /*struct iterator_traits*/;
} /*namespace std*/;
You can also choose to place these type aliases directly in the iterator class itself. Regardless, algorithms can now specialize upon the type of iterator_category and implement specific versions for specific categories.
The code is as follows
template<class T>
class arrayList {
public:
// constructor, copy constructor and destructor
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList() {
delete[] element;
}
class seamlessPointer;
seamlessPointer begin() {
return seamlessPointer(element);
}
seamlessPointer end() {
return seamlessPointer(element + listSize);
}
// iterator for arrayList
class iterator
{
public:
// typedefs required by C++ for a bidirectional iterator
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
// constructor
iterator(T* thePosition = 0) {position = thePosition;}
// dereferencing operators
T& operator*() const {return *position;}
T* operator->() const {return position;}
// increment
iterator& operator++();
{++position; return *this;}
iterator operator++(int);
// decrement
iterator& operator--();
iterator operator--(int) ;
// equality testing
bool operator!=(const iterator right) ;
bool operator==(const iterator right) ;
protected:
T* position;
}; // end of iterator class
class seamlessPointer: public arrayList<T>::iterator {
public:
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
// constructor
seamlessPointer(T *thePosition);
seamlessPointer(const seamlessPointer & rhs);
//arithmetic operators
seamlessPointer operator+(int n) ;
seamlessPointer operator-(int n) ;
};
protected:
T* element; // 1D array to hold list elements
int arrayLength; // capacity of the 1D array
int listSize; // number of elements in list
};
c:\wascana\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_algo.h:5250:4: error: no match for 'operator-' in '__last - __first'
Looking over your code it appears that you've got the right kinds of ideas by including those typedefs with your own iterator implementation. However, why go to all the trouble in the first place when something else could do it for you? Have you looked at iterator_traits or the standard iterator? They just add typedefs to your code which will aid you in developing new iterator types.