So I'm working with templates and I've run into a problem. After I converted my code into templates I am no longer able to access the private members of my classes. I get the error that 'current' is a private member of 'Iterator'. So first I have each class:
template <class T>
struct nodeType {
T info;
nodeType<T> *link;
};
template <class T>
class Iterator {
public:
Iterator();
Iterator(nodeType<T> *);
T operator*();
bool IsNull();
Iterator<T> operator++();
Iterator<T> operator++(int);
bool operator==(const Iterator<T> &) const;
bool operator!=(const Iterator<T> &) const;
Iterator<T> &operator=(T);
private:
nodeType<T> *current;
};
template <class T>
class LinkedList {
public:
LinkedList();
LinkedList(const LinkedList<T> &);
~LinkedList();
void InsertHead(T);
Iterator<T> InsertAfter(T, Iterator<T>);
Iterator<T> Search(T);
bool IsEmpty();
void Print();
void DestroyList();
Iterator<T> Start();
Iterator<T> End();
const LinkedList<T> &operator=(const LinkedList<T> &);
private:
nodeType<T> *head;
};
Before I used templates I used the following code, but not current is private and this no longer works.
template <class T>
Iterator<T> LinkedList<T>::InsertAfter(T input, Iterator<T> marker) {
Iterator<T> newNode = new nodeType<T>;
Iterator<T> findNode = marker;
newNode = input;
newNode.current->link = findNode.current->link;
findNode.current->link = newNode.current;
return findNode;
}
Then I tried to do the following and It get no errors but when I called the InsertAfter function to add a new item to the list it doesn't show up. I did a cout newNode = input; and it shows the value I want to insert, but the nodes don;t seem to connect up. Why can't I use the previous code I was doing before? Like newNode.current->link = findNode.current->link;
template <class T>
Iterator<T> Iterator<T>::operator++() {
current = current->link;
return *this;
}
template <class T>
Iterator<T> Iterator<T>::operator++(int) {
Iterator<T> temp;
temp = *this;
++(*this);
return temp;
}
template <class T>
Iterator<T> LinkedList<T>::InsertAfter(T input, Iterator<T> marker) {
Iterator<T> newNode = new nodeType<T>;
Iterator<T> findNode = marker;
newNode = input;
newNode++ = findNode++;
findNode++ = newNode;
return findNode;
}
You can't do newNode.current within a member function of LinkedList, because current is private to Iterator. That's what private means - it is only accessible from member functions of the class it belongs in.
Clearly your "old" code was different. Possibly you had Iterator friend LinkedList in the old code. If you post your old code it might clear things up.
Related
I've created a custom Node, Iterator and List.
I would like to do:
List<int> list;
// push_back objects here...
List<int>::Iterator it = list.begin();
list.erase(it);
++it;
list.erase(it); // error here
So I need to reconstruct the iterator after erasing an element. How do I do that?
Node.h
#pragma once
namespace Util
{
template<typename T>
class Node
{
public:
template<typename T> friend class Iterator;
template<typename T> friend class List;
private:
Node();
Node(T);
~Node();
/* unlink(): takes out this node
and links next and prev to each other
prev <- this -> next
prev <- -> next
this <- this -> this
*/
void unlink();
private:
T value;
Node<T>* next;
Node<T>* prev;
};
template<typename T>
Node<T>::Node() : next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::Node(T t) : value(t), next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::~Node()
{
unlink();
}
template<typename T>
void Node<T>::unlink()
{
next->prev = prev;
prev->next = next;
next = this;
prev = this;
}
}
Iterator.h
#pragma once
#include "Node.h"
namespace Util
{
template<typename T>
class Iterator
{
public:
template<typename T> friend class List;
Iterator& operator++();
T& operator*() const;
bool operator==(const Iterator& rhs) const;
bool operator!=(const Iterator& rhs) const;
private:
Iterator(Node<T>* n);
Node<T>* node;
};
template<typename T>
Iterator<T>::Iterator(Node<T>* n) : node(n)
{
// ...
}
template<typename T>
Iterator<T>& Iterator<T>::operator++()
{
node = node->next;
return *this;
}
template<typename T>
T& Iterator<T>::operator*() const
{
return node->value;
}
template<typename T>
bool Iterator<T>::operator==(const Iterator& rhs) const
{
return node == rhs.node;
}
template<typename T>
bool Iterator<T>::operator!=(const Iterator& rhs) const
{
return node != rhs.node;
}
}
List.h
#pragma once
#include "Iterator.h"
namespace Util
{
template<typename T>
class List
{
public:
typedef Iterator<T> Iterator;
typedef Node<T> Node;
List();
~List();
// Capacity
bool empty() const;
int size() const;
// Modifiers
void push_back(const T&);
void push_front(const T&);
void pop_back();
void pop_front();
Iterator erase(Iterator it);
// Element access
Iterator begin() const;
Iterator end() const;
private:
Node* head;
int list_size;
};
template<typename T>
List<T>::List() : list_size(0)
{
head = new Node();
}
template<typename T>
List<T>::~List()
{
while (!empty()) pop_back();
delete head;
}
template<typename T>
bool List<T>::empty() const
{
return head->next == head;
}
template<typename T>
int List<T>::size() const
{
return list_size;
}
template<typename T>
void List<T>::push_back(const T& t)
{
Node* n = new Node(t);
n->next = head;
n->prev = head->prev;
head->prev->next = n;
head->prev = n;
++list_size;
}
template<typename T>
void List<T>::push_front(const T& t)
{
Node* n = new Node(t);
n->prev = head;
n->next = head->next;
head->next->prev = n;
head->next = n;
++list_size;
}
template<typename T>
void List<T>::pop_back()
{
if (head->prev == head) return;
delete head->prev;
--list_size;
}
template<typename T>
void List<T>::pop_front()
{
if (head->next == head) return;
delete head->next;
--list_size;
}
template<typename T>
typename List<T>::Iterator List<T>::erase(Iterator it)
{
if (it.node == head) return it;
Node* n = it.node->next;
delete it.node;
--list_size;
return Iterator(n);
}
template<typename T>
typename List<T>::Iterator List<T>::begin() const
{
return Iterator(head->next);
}
template<typename T>
typename List<T>::Iterator List<T>::end() const
{
return Iterator(head);
}
}
Edit: after updating the code based on the comments I received. Going through the list and erasing, only erases every other element; since the loop is incrementing the iterator and erase makes the iterator's current object iterator's next object. Is this how it is in the standard as well?
for (Util::List<int>::Iterator it = list.begin(); it != list.end(); ++it)
{
it = list.erase(it);
}
Old list: 0 1 2 3 4 5 6 7 8 9
After erasing: 1 3 5 7 9
Please do not complain about rule of five and things unrelated to the question. I haven't gotten to every part yet. My justification of making an edit over posting a new question is that the edit is still about how to reconstruct the iterator correctly after erase.
As some people already mentioned, erase typically returns a new, valid iterator, if that is possible/feasible for the container.
You can define the semantics as you would like, but typically you would erase the element by pointing prev->next to next and next->prev to prev, then deallocate the node, and return an iterator to next. You could also return an iterator to prev, but that results in several counter-intuitive behaviors, such as having to advance the iterator if you are doing an operation on some sort of range. Returning an iterator to next, just lets you delete ranges with while(foo(it)) it = c.erase(it);
In that case you of course don't increment the iterator anymore, unless you wan t to skip every other element.
I have the following code:
#include <iostream>
using namespace std;
template <class T>
class Iterator;
template <class T>
class List;
template <class T>
class List {
public:
struct Node;
Node* first;
friend class Iterator<T>;
List() :
first(NULL) { }
Iterator<T> begin() {
cout << first->data << endl;
return Iterator<T>(*this, first); // <--- problematic call
}
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
};
template <class T>
struct List<T>::Node {
private:
T data;
Node* next;
friend class List<T>;
friend class Iterator<T>;
Node(const T& data, Node* next) :
data(data), next(next) { }
};
template <class T>
class Iterator {
private:
const List<T>* list;
typename List<T>::Node* node;
friend class List<T>;
public:
Iterator(const List<T>& list, typename List<T>::Node* node) {
cout << node->data << endl;
}
};
int main() {
List<int> list;
list.insert(1);
list.begin();
return 0;
}
First I set the node data to "1" (int). Ater that I just pass it to the Iterator constructor, but it changes the value of node->data.
I printed node->data before and after the call:
1
2293232
I guess that 2293232 is an address of something, but I can't find the reason this happens.
When you write
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
Then:
You create an object on the stack
Point some (more) persistent pointer to its address
Destruct it as it goes out of scope
So you're left with garbage stuff.
so thats what i got going.
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator;
template <class T>
class List<T>::Iterator{
public:
Iterator& operator++();
i'm trying to implement like so:
template<class T>
typename List<T>::Iterator& List<T>::Iterator::operator++()
but it keeps telling me "Member declaration not found"
EDIT:
thats the entire relevent code:
template <class T>
class Node {
T data;
Node<T>* next;
public:
Node () : next(0){};
Node (const T& info, Node<T>* next = 0) : data(info), next(next){};
friend class List<T>;
friend class Iterator;
friend class ConstIterator;
};
template<class T>
class List{
Node<T> head;
int size;
void listSwap(Node<T>* node1, Node<T>* node2);
public:
class Iterator;
class ConstIterator;
List ();
List(const List<T>& list);
List& operator=(const List<T>& list);
ConstIterator begin() const;
Iterator begin();
ConstIterator end() const;
Iterator end();
void insert(const T& t);
void insert(const T& t,const Iterator& it);
void remove(const Iterator& it);
// template<class Function>
// ConstIterator find(Function f);
template<class Function>
Iterator find(Function f);
template<class Function>
void sort(Function f);
int getSize();
bool operator==(const List<T>& list2) const;
bool operator!=(const List<T>& list2) const;
~List();
};
template <class T>
class List<T>::Iterator{
List<T>* list;
Node<T>* index;
public:
Iterator(List<T> list);
Iterator(List<T> list, Iterator& it);
Iterator& operator++();
Iterator operator++(int);
T operator*();
bool operator==(const Iterator& iterator2);
bool operator!=(const Iterator& iterator2);
~Iterator();
friend class List<T>;
};
thought I think it is ok :/
so frustrating sometimes....
Thank you guys for the help!
You don't need template<class T> class List<T>::Iterator in the Iterator class definition if iterator is a nested class. Just class Iterator.
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator
{
public:
Iterator& operator++();
....
};
....
};
Either that, or you are missing the closing }; of your List class:
template<class T>
class List{
Node<T> head;
int size;
public:
class Iterator;
};
^^ HERE!
I see some obvious bugs, as the class List is not closed before you define List<T>::Iterator, but I presume it is so because you cut off some portion of your code.
Unfortunately, I was unable to reproduce your case. The following code:
class List {
int size;
public:
class Iterator;
};
template <class T>
class List<T>::Iterator {
public:
Iterator& operator++();
};
template <class T>
typename List<T>::Iterator& List<T>::Iterator::operator++() {
return *this;
}
int main() {
}
And it compiles just fine under g++ (4.6.3) and clang++ (3.1), so the problem is somewhere else which you are not showing us.
You first code sample seems to be shreeded beyond recognition.
As for your second (longer) section of code, I don't see anthing wrong with it aside from one suspect area. Your friend declarations inside Node will refer to some non-template Iterator and ConstIterator classes from global namespace. Meanwhile, Iterator and ConstIterator from List are templates that do not belong to global namespace. Were those friend declarations in Node supposed to refer to Iterator and ConstIterator from List or not?
I hope this hasn't been covered in some question before. I looked as best I could, but I think part of the problem in the first place is that I don't understand what is up, and that may have prevented me from finding a previous answer. My apologies if so, but otherwise...
For practice with templates and generally understanding C++ and code design better, I've set to writing a (currently quite simple) implementation of a linked list, mostly seeking to mimic std::list. I've been working at implementing iterators properly, and the other components logically, but I've run into a snag. I'd guess it is with template syntax somewhere, but I'm not sure. It could be just some silly mistake.
Here's the general structure of the class:
template <class T>
class LinkedList {
public:
LinkedList();
class Iterator;
void push_front(const T&);
void push_back(const T&);
void pop_front();
void pop_back();
T& front();
T& back();
unsigned int size() const;
bool empty() const;
Iterator begin();
Iterator end();
private:
struct ListNode;
ListNode* m_front;
ListNode* m_back;
unsigned int m_size;
};
template <class T>
class LinkedList<T>::Iterator {
public:
Iterator();
Iterator(const Iterator& rhs);
Iterator(ListNode* const& node);
Iterator operator=(const Iterator& rhs);
T& operator*();
bool operator==(const Iterator& rhs) const;
bool operator!=(const Iterator& rhs) const;
Iterator operator++();
private:
ListNode* m_node;
};
template <class T>
struct LinkedList<T>::ListNode {
T* m_data;
ListNode* m_next;
};
And here is the offending function:
template <class T>
void LinkedList<T>::push_front(const T&) {
if (m_front == NULL) {
m_front = new ListNode;
*(m_front->m_data) = T;
m_front->m_next = NULL;
m_back = m_front;
} else if (m_front == m_back) {
m_front = new ListNode;
*(m_front->m_data) = T;
m_front->m_next = m_back;
} else {
ListNode* former_front(m_front);
m_front = new ListNode;
*(m_front->m_data) = T;
m_front->m_next = former_front;
}
}
And the error given by GCC 4.6.3:
linkedlist.hpp: In member function ‘void pract::LinkedList<T>::push_front(const T&)’:
linkedlist.hpp:75:31: error: expected primary-expression before ‘;’ token
linkedlist.hpp:80:31: error: expected primary-expression before ‘;’ token
linkedlist.hpp:85:31: error: expected primary-expression before ‘;’ token
I hope all that helps, but if anything else would be desirable please do ask.
Thanks all.
The problems is on these lines:
*(m_front->m_data) = T;
This is attempting to assign a type to a variable, which is clearly not possible. Probably you want a named argument and to use said argument for this assignment:
template <class T>
void LinkedList<T>::push_front(const T& t) {
if (m_front == NULL) {
m_front = new ListNode;
*(m_front->m_data) = t;
m_front->m_next = NULL;
m_back = m_front;
} else if (m_front == m_back) {
m_front = new ListNode;
*(m_front->m_data) = t;
m_front->m_next = m_back;
} else {
ListNode* former_front(m_front);
m_front = new ListNode;
*(m_front->m_data) = t;
m_front->m_next = former_front;
}
}
I've just started with learning C++ and I need to write a generic linked list and iterator. This is the code that I wrote (list.h), but I think it is not correct. It does not work and I am not sure that it is generic.
#include <iostream>
#include <cassert>
using namespace std;
using namespace ListExceptions;
class List;
class Iterator;
template<class T>
class Node{
private:
T data;
Node* previous;
Node* next;
friend class List;
friend class Iterator;
public:
Node(T element){
data = element;
previous = NULL;
next = NULL;
}
};
class List{
private:
Node* first;
Node* last;
public:
List(){
first = NULL;
last = NULL;
}
void pushBack(T element);
void insert(Iterator iter, T element);
Iterator remove(Iterator i);
Iterator find(const Predicate& predicate);
void sort(const Compare& comparer);
int getSize() const;
Iterator begin();
Iterator end();
};
class Iterator{
private:
Node* position;
Node* last;
friend class List;
public:
Iterator();
void next();
T getElement()const;
bool equals(Iterator b) const;
bool notEquals(Iterator b) const;
};
If someone can help me?
First thing is that the List and Iterator are non-templated classes, and you probably want to create Lists of a given type. You might consider refactoring the code so that both the Node and the Iterator are internal classes to the List type (it will make things simpler):
template <typename T>
class List {
public:
typedef T value_type;
class Iterator;
struct Node { // Internal to List<T>, so there will be different
// List<T>::Node for each instantiationg type T
// But you don't need the extra <T> parameter for List
// or Iterator
value_type data;
Node* next;
Node* last;
friend class List; // Inside List<T>, List by itself refers to List<T>
friend class Iterator;
};
//...
};
The alternative is a little more complex in code:
template <typename T> class List;
template <typename T> class Iterator;
template <typename T> class Node {
T data;
Node * next;
Node * last;
friend class List<T>;
friend class Iterator<T>;
};
template <typename T>
class List {
Node<T>* first; // note <T> required
//...
};