I'm trying to implement a linked list with a template class LList and Nested Iterator and Node classes. Here's the code:
template <typename T1>
class LList
{
public:
class Iterator
{
public:
Iterator();
T1 get() const;
void next();
void previous();
bool equals(Iterator iter) const;
private:
Node* position;
LList* container;
};
LList();
~LList();
void pushBack(T1 data);
Iterator begin();
Iterator end();
void insert (Iterator iter, T1 data);
Iterator erase(Iterator Iter);
private:
class Node
{
public:
Node(T1 data);
private:
T1 data;
Node* ptr_next;
Node* ptr_prev;
};
Node* ptr_first;
Node* ptr_last;
};
template <typename T1>
LList<T1>::Node::Node(T1 data)
{
this->data = data;
ptr_next = 0;
ptr_prev =0;
}
template <typename T1>
LList<T1>::Iterator::Iterator()
{
position = 0;
container = 0;
}
template <typename T1>
T1 LList<T1>::Iterator::get() const
{
return position->data;
}
template <typename T1>
void LList<T1>::Iterator::next()
{
if(position == container->ptr_last)
{
position = container->ptr_first;
}
else
{
position = position->ptr_next;
}
}
template <typename T1>
void LList<T1>::Iterator::previous()
{
if(!position)
{
position = container->ptr_last;
}
else
{
position = position->ptr_prev;
}
}
template <typename T1>
bool LList<T1>::Iterator::equals(Iterator iter) const
{
return position == iter.position;
}
template <typename T1>
LList<T1>::LList()
{
ptr_first = 0;
ptr_last = 0;
}
template <typename T1>
LList<T1>::~LList()
{
while (ptr_first)
{
Node* tmp = ptr_first;
ptr_first = ptr_first->ptr_next;
delete tmp;
tmp = 0;
}
}
template <typename T1>
void LList<T1>::pushBack(T1 data)
{
Node* new_node = new Node(data);
if(ptr_first==0)
{
ptr_first = new_node;
ptr_last = new_node;
}
else
{
ptr_last->ptr_next = new_node;
new_node->ptr_prev = ptr_last;
ptr_last = new_node;
}
}
template <typename T1>
Iterator LList<T1>::begin()
{
Iterator iter;
iter.positon = ptr_first;
iter.container = this;
return iter;
}
template <typename T1>
Iterator LList<T2>::end()
{
Iterator iter;
iter.position = ptr_last;
iter.container = this;
return iter;
}
template <typename T1>
void LList<T1>::insert(Iterator iter, T1 data)
{
if (iter.position == 0)
{
pushBack(data);
return;
}
Node* before;
Node* after;
after = iter.position;
before = iter.position->ptr_prev;
Node* new_node = new Node(data);
after->ptr_prev = new_node;
if (before == 0) ptr_first = new_node;
else before->ptr_next = new_node;
new_node->ptr_prev = before;
new_node->ptr_next = after;
}
template <typename T1>
Iterator LList<T1>::erase(Iterator iter)
{
Node* after = iter.position->ptr_next;
Node* before = iter.position->ptr_prev;
Node* remove = iter.position;
if (remove == ptr_first) ptr_first = after;
else before->ptr_next = after;
if (remove == ptr_last) ptr_last = before;
else after->ptr_prev = before;
delete remove;
remove = 0;
}
I've seen how do it without nested classes but I need to do it with a nested class.
Any help on why it doesn't compile will help :) Thanks.
Well, Iterator is the name of a nested class, so when you use it in the definition of a member function of your LList class template as the return type, you have to fully qualify it (and add the typename disambiguator to tell the compiler that what follows the :: shall be parsed as the name of a type).
For instance:
template <typename T1>
typename LList<T1>::Iterator LList<T1>::erase(Iterator iter)
// ^^^^^^^^^^^^^^^^^^^^
There are several instances of this error, so you will have to fix all of them.
You are also referring to class Node before its definition appears inside LList. Therefore, you should have a forward declaration for it:
template <typename T1>
class LList
{
class Node;
// ^^^^^^^^^^^
// Forward declaration for Node
public:
// ...
class Iterator
{
// ...
Node* position; // <== Now this is OK because of the forward declaration
// ...
};
There are different error :
The first is that you use Node into the Iterator class, but you need to declare Node before it :
template <typename T1>
class LList
{
private:
class Node
{
public:
Node(T1 data);
private:
T1 data;
Node* ptr_next;
Node* ptr_prev;
};
Node* ptr_first;
Node* ptr_last;
public:
LList();
~LList();
void pushBack(T1 data);
class Iterator
{
public:
Iterator();
T1 get() const;
void next();
void previous();
bool equals(Iterator iter) const;
private:
Node* position;
LList* container;
};
Iterator begin();
Iterator end();
void insert (Iterator iter, T1 data);
Iterator erase(Iterator Iter);
};
That is the first thing.
The second is that Iterator is a nested type, so you need to be more specific when you return un object of this type :
template <typename T1>
typename LList<T1>::Iterator LList<T1>::begin()
And the last error is :
template <typename T1>
Iterator LList<T2>::end()
Here is the correct lign :
template <typename T1>
typename LList<T1>::Iterator LList<T1>::end()
// ^^^^^^^^^^^^^^^^^ ^^
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 implemented my custom allocator and custom list container, which supports this allocator. They are defined like so:
template <typename T, size_t num_of_blocks = 16>
class MyAllocator {
public:
template <typename U>
struct rebind {
using other = MyAllocator<U, num_of_blocks>;
}
...dozens of standard methods
}
template <typename T, typename MyAlloc = std::allocator<Node<T>>>
class MyList {
private:
MyAlloc allocator;
...different methods which use allocator member
}
It all works good. So, in my client code, I can do it like:
auto my_list = MyList<int, MyAllocator<Node<int>,10>>{};
It works without errors and I see, that my custom allocator is used. But I do not like the way I use my custom allocator. In fact, I want my client code look like:
auto my_list = MyList<int, MyAllocator<int,10>>{};
My first attempt was this:
template <typename T, typename MyAlloc = std::allocator<T>>
class MyList {
private:
//MyAlloc allocator; // remove this member and rebind allocator to another one
typedef typename MyAlloc::template rebind<Node<T>>::other node_alloc_type;
node_alloc_type allocator; // I expect that my allocator now is of type MyAllocator<Node<T>, num_of_blocks>
... all the rest left unchanged
}
When however I run my new client code:
auto my_list = MyList<int, MyAllocator<int,10>>{};
I get these error messages:
can not convert 'int*' to 'Node*'in assignment
I'm not sure what I'm doing wrong and what I'm missing. So, how can I fix it? And what is the right way to use rebind in custom container?
EDIT
That is how my custom container looks like now:
//MyList.h
#include <memory>
template<typename T>
struct Node
{
Node(): m_next(nullptr){}
Node(T const &t):
m_value(t),
m_next(nullptr)
{}
T m_value;
Node* m_next;
};
template<typename T, typename MyAllocator = std::allocator<Node<T>>>
class MyList
{
private:
Node<T>* m_head = nullptr;
Node<T>* m_tail = nullptr;
MyAllocator my_allocator;
public:
class Iterator
{
private:
Node<T>* m_Node;
public:
Iterator(Node<T>* Node): m_Node(Node) {};
bool operator==(const Iterator& other)
{
return this == &other || m_Node == other.m_Node;
}
bool operator!=(const Iterator& other)
{
return !operator==(other);
}
T operator*()
{
if (m_Node)
{
return m_Node->m_value;
}
return T();
}
Iterator operator++()
{
Iterator i = *this;
if (m_Node)
{
m_Node = m_Node->m_next;
}
return i;
}
};
template<typename... Args>
void emplace(T v)
{
auto new_Node = my_allocator.allocate(1);
my_allocator.construct(new_Node, v);
if (m_head)
{
m_tail->m_next = new_Node;
} else {
m_head = new_Node;
new_Node->m_next = nullptr;
}
m_tail = new_Node;
}
Iterator begin() const
{
return Iterator(m_head);
}
Iterator end() const
{
return Iterator(nullptr);
}
};
At this moment there is no rebinding and I have to define it like
template<typename T, typename MyAllocator = std::allocator<Node<T>>>
class MyList
What I want is to define it like so:
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
EDIT
Here is a client code with standard allocator:
//main.cpp
#include "MyList.h"
int main()
{
MyList<int, std::allocator<Node<int>>> my_list;
//auto my_list = MyList<int, std::allocator<int>>; // will not work
for (int i = 0; i < 10; ++i)
{
my_list.emplace(i);
}
return 0;
}
These are the requirements for an allocator: http://en.cppreference.com/w/cpp/concept/Allocator
Notice that template rebind is optional.
Here is a list of what a container must have in order to qualify for the concept. http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer
Yes, gasp. I have searched in vain for a simple, or at least minimalist example. If all you need is a linked list, and you can use C++11 or later, use std::forward_list.
The following works in the example given.
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
{
private:
using node_alloc_t = typename std::allocator_traits<MyAllocator>::
template rebind_alloc<Node<T>>;
// create an object of type node allocator
node_alloc_t node_alloc;
// etc ....
public:
template<typename T>
void emplace(T v)
{
Node<T>* new_Node = node_alloc.allocate(1);
// Etc...
}
// etc...
};
All together now...
#include <memory>
#include <iostream>
template<typename T>
struct Node
{
Node() : m_next(nullptr) {}
Node(T const &t) :
m_value(t),
m_next(nullptr)
{}
T m_value;
Node<T>* m_next;
};
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
{
private:
using node_alloc_t = typename std::allocator_traits<MyAllocator>::
template rebind_alloc<Node<T>>;
// create an object of type node allocator
node_alloc_t node_alloc;
public:
class Iterator
{
private:
Node<T>* m_Node;
public:
Iterator(Node<T>* Node) : m_Node(Node) {};
bool operator==(const Iterator& other)
{
return this == &other || m_Node == other.m_Node;
}
bool operator!=(const Iterator& other)
{
return !operator==(other);
}
T operator*()
{
if (m_Node)
{
return m_Node->m_value;
}
return T();
}
Iterator operator++()
{
Iterator i = *this;
if (m_Node)
{
m_Node = m_Node->m_next;
}
return i;
}
};
template<typename T>
void emplace(T v)
{
Node<T>* new_Node = node_alloc.allocate(1);
node_alloc.construct(new_Node, v);
if (m_head)
{
m_tail->m_next = new_Node;
}
else {
m_head = new_Node;
new_Node->m_next = nullptr;
}
m_tail = new_Node;
}
Iterator begin() const
{
return Iterator(m_head);
}
Iterator end() const
{
return Iterator(nullptr);
}
};
int main()
{
MyList<int> my_list;
for (int i = 0; i < 10; ++i)
{
my_list.emplace(i);
}
for (auto i : my_list) {
std::cout << i << std::endl;
}
return 0;
}
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.
I've created a simple dynamic template list and i'm having some issue clearing the entire list.
List.h
#ifndef LIST_H
#define LIST_H
#include <Node.h>
template <class T> class List
{
public:
typedef Node<T> node_type;
typedef node_type* node_pointer;
typedef T data_type;
typedef T& reference_type;
List();
void push_back(data_type);
reference_type at(int);
void clear();
void swap(int,int);
int size();
private:
int list_size = 0;
node_pointer head, tail;
};
template <class T> List<T>::List()
{
head=NULL;
tail=NULL;
}
template <class T> void List<T>::push_back(data_type data)
{
if(head == NULL) {
head = new node_type(data);
tail = head;
} else {
node_pointer temp = new node_type(data);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
list_size++;
}
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
node_pointer pointer=head;
for(int i=0; i<x; i++)
pointer=pointer->getNext();
return pointer->getData();
}
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
for(int i=0; i<list_size; i++) {
node_pointer temp = pointer;
pointer=pointer->getNext();
delete(temp);
}
head=NULL;
list_size=0;
}
template <class T> void List<T>::swap(int x, int y)
{
data_type buffer=at(x);
at(x)=at(y);
at(y)=buffer;
}
template <class T> int List<T>::size()
{
return list_size;
}
#endif // LIST_H
Node.h
template <class T> class Node
{
public:
typedef T data_type;
typedef T& reference_type;
Node(data_type _data);
void setData(data_type);
void setNextNull();
void setNext(Node*);
reference_type getData();
Node* getNext();
private:
data_type data;
Node* next;
};
template <class T> Node<T>::Node(data_type _data) : data(_data)
{
setNextNull();
}
template <class T> void Node<T>::setData(data_type _data)
{
data=_data;
}
template <class T> void Node<T>::setNextNull()
{
next=NULL;
}
template <class T> void Node<T>::setNext(Node* _next)
{
next=_next;
}
template <class T> typename Node<T>::reference_type Node<T>::getData()
{
return data;
}
template <class T> typename Node<T>::Node* Node<T>::getNext()
{
return next;
}
If I clear the list calling the "clear" method I get all sorts of errors in almost every other method, but if I use the version below the list works perfectly.
template <class T> void List<T>::clear()
{
head=NULL;
tail=NULL;
list_size=0;
}
The problem only appears if I use the delete function to clear memory. How can I solve this issue?
Your code is very dangerious, because you skipped important checks. Try to use following implementation of at():
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
if (x < 0 || x >= list_size || list_size <= 0)
return DATA_WITH_ERROR_FLAG; // since you return data instead of pointer,
// you can't return NULL here
// (you need special constant for error status
// or support it another way)
node_pointer pointer=head;
for(int i=0; i<x; i++)
{
if (!pointer)
return DATA_WITH_ERROR_FLAG;
pointer=pointer->getNext();
}
if (!pointer)
return DATA_WITH_ERROR_FLAG;
return pointer->getData();
}
After it you have to add checks after each at() call. For example, you have to modify swap() to make it safe too:
template <class T> void List<T>::swap(int x, int y)
{
data_type v1=at(x);
data_type v2=at(y);
if (v1 == DATA_WITH_ERROR_FLAG || v2 == DATA_WITH_ERROR_FLAG)
return; // and somehow set error flag!
data_type t=v1;
v1 = v2;
v2 = t;
}
I.e. you need to check correctness everywhere if you don't like such problems. And it is necessary to support returninig of error status to simplify analysis of errors.
Change your clear() method to this:
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
while (pointer != NULL) {
node_pointer temp = pointer-getNext();
delete pointer;
pointer = temp;
}
head=NULL;
tail=NULL;
list_size=0;
}
You have a memory leak in your code. You don't delete all the list by simply pointing head and tail to NULL.
The best way to do this is to create a delete() function then loop through the whole list while it is not empty and delete node by node.
void deleteHead()
{
if(head != NULL)
{
node *temp = head;
head = head->next;
delete temp;
size--;
}
}
bool isEmpty()
{
return head==NULL;
//return size == 0; <-- this is ok as well.
}
void clear()
{
while(! isEmpty())
{
deleteHead();
}
tail = head; //head = NULL
}
My sort function looks like this:
template <typename Compare, typename T>
void List<T>::sort(const Compare& comparer){
...
}
But I received next error:
template definition of non-template
void List<T>::sort(const Compare&)'
invalid use of undefined typeclass
List'
What does it mean?
This is the complete code of the list:
template <typename T> class Node;
template <typename T> class Iterator;
template <typename T>
class List{
private:
Node<T> * first;
Node<T> * last;
int size;
friend class Predicate ;
friend class Compare;
public:
typedef Iterator<T> iterator;
List(){
first = NULL;
last = NULL;
size = 0;
}
List(const List<T> & l);
void pushBack(T element);
void insert( const T& element, iterator i);
iterator remove(iterator i);
iterator find(const Predicate& predicate);
void sort(const Compare& comparer);
int getSize() const;
iterator begin();
iterator end();
~List();
};
template <class T>
List<T>::List(const List & l) {
first = 0;
last = 0;
size = 0;
for (Node<T> * current = l.first; current != 0; current = current -> next){
pushBack(current -> data);
}
}
template <typename T>
void List<T>::pushBack(T element){
Node<T>* newnode = new Node<T>(element);
if (newnode->prev == NULL) {
first = newnode;
last = newnode;
}else{
newnode->prev = last;
last->next = newnode;
last = newnode;
}
}
template <typename T>
void List<T>::insert( const T& element, iterator i){
if (i.position == NULL){
pushBack(element);
++size;
return;
}
Node<T>* after = i.position;
Node<T>* before = after->prev;
Node<T>* newnode = new Node<T>(element);
newnode->prev = before;
newnode->next = after;
after->prev = newnode;
if (before == NULL) {
first = newnode;
}
else{
before->next = newnode;
}
++size;
}
template <typename T>
typename List<T>::iterator List<T>::remove(iterator iter){
if(iter.position != NULL){
Node<T>* remove = iter.position;
Node<T>* before = remove->prev;
Node<T>* after = remove->next;
if (remove == first){
first = after;
} else{
before->next = after;
}
if (remove == last){
last = before;
}else{
after->prev = before;
}
iter.position = after;
--size;
delete remove;
return iter;
}else{
throw ElementNotFound();
}
}
template <typename T>
typename List<T>::iterator List<T>::begin(){
//iterator iter;
//iter.position = first;
//iter.last = last;
return iterator(first);
}
template <typename T>
typename List<T>::iterator List<T>::end(){
return iterator (last);
}
template <typename Predicate, typename T>
List<T>::iterator List<T>::find(const Predicate& predicate){
iterator iter;
for( iter = begin(); iter != end(); iter = next()){
if( predicate(iter.getElement())){
return iter;
}
}
return end();
}
template <typename Compare, typename T>
void List<T>::sort(const Compare& comparer){
Iterator<T> iter;
for( iter = begin(); iter != end(); iter = iter.next() ){
if( comparer( iter.getElement() , (iter+1).getElement()) != true){
}
}
}
template <typename T>
int List<T>::getSize() const{
return size;
}
template <class T>
List <T>::~List() {
Node <T> * firstNode = first;
while (firstNode != 0) {
Node <T> * nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
template <typename T> class Node {
private:
T data;
Node* next;
Node* prev;
friend class List<T>;
friend class Iterator<T>;
public:
Node(T element){
data = element;
prev = NULL;
next = NULL;
}
~Node(){}
};
template <typename T> class Iterator{
private:
Node<T>* position;
Node<T>* last;
friend class List<T>;
public:
Iterator(){
position = NULL;
last = NULL;
}
Iterator(Node<T> * source): position(source) { }
T& getElement()const;
bool operator==(Iterator b) const;
bool operator!=(Iterator b) const;
T & operator*();
Iterator & operator++();
Iterator & operator++(int);
~Iterator(){}
};
template <class T>
T& Iterator<T>::getElement() const{
if(position != NULL){
return position->data;
}
else{
throw ElementNotFound();
}
}
template <typename T>
bool Iterator<T>::operator==(Iterator b) const{
return position == b.position;
}
template <typename T>
bool Iterator<T>::operator!=(Iterator b) const{
return position != b.position;
}
template <typename T>
T & Iterator<T>::operator*() {
return position->data;
}
template <class T>
Iterator<T> & Iterator<T>::operator++() {
position = position->next;
return *this;
}
template <class T>
Iterator<T> & Iterator<T>::operator++(int){
position = position->next;
return *this;
}
#endif /* LISTGENERIC_H_ */
Either you declare sort as a template function with one template argument (Compare) inside the class. Then your definition has to look as follows:
template <typename T>
template <typename Compare>
void List<T>::sort(const Compare& comparer) {
…
}
And you also need to remove the now redundant friend class Compare declaration from your List class.
Or you keep Compare and sort as-is. In this case, simply don’t have sort as a template, and omit the Compare template argument:
template <typename T>
void List<T>::sort(const Compare& comparer) {
…
}
Of course this only works if you have defined (not just declared!) the class Compare before this function.
But this second solution would be highly unorthodox and pretty useless since the compare argument doesn’t make much sense: there is only one Compare class and the user cannot change it. Normally, this should be a template argument (first solution).