I am new to templates in C++ and am working on a project where I need to implement a Doubly Linked List using a template. However, I can't seem to access the node elements next and previous.
For example, in my destructor, I cannot use curr-> to bring up my options of using next or prev. IntelliSense just says, "No members available." Also, I can only find errors during build time...no red lines, warnings, anything appear beforehand. I am curious as to why this is not working....is it a bug or intended? If it is, where is my template incorrect thus far?
template<class ItemType>
class SortedList
{
public:
SortedList();
~SortedList();
bool Insert (ItemType toAdd);
bool Delete (ItemType toDelete);
void Print();
private:
SortedList ( const SortedList & copyFrom );
SortedList & operator= ( const SortedList & assignFrom );
struct Node
{
Node ( ItemType item, Node * p = NULL, Node * n = NULL )
{ data = item; prev = p; next = n; }
ItemType data;
Node * prev, * next;
};
Node * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list = NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node * curr = list;
while ( curr != NULL )
{
Node * tempNext = curr->next;
delete curr;
curr = tempNext;
}
}
Put the Node struct out of the SortedList like this:
template<typename ItemType>
struct Node
{
Node(ItemType item, Node * p = NULL, Node * n = NULL)
{
data = item; prev = p; next = n;
}
ItemType data;
Node * prev, *next;
};
and then instantiate the template (create the type) inside SortedList like this:
template<class ItemType>
class SortedList
{
public:
//... More code here.
private:
// ... More code here.
Node<ItemType> * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list = NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node<ItemType> *curr = list;
while (curr != NULL)
{
Node * tempNext = curr->next; // Now this will work.
delete curr;
curr = tempNext;
}
}
The logic I have followed
A template, is not a type. You get the type instantiating the template. Hence the type Node Does not exists until you instantiate the template StortedList since the former is inside the latter.
Also the exact type for Node would be SortedList<ItemType>::Node, and there you can see you can't talk about Node, before compiling the code. Thats why IntelliSense don't "see it".
Related
I am working with Templates and defined the below templated ListNode.
template <typename T>
class ListNode{
private :
public:
ListNode *left;
ListNode *right;
T data;
ListNode(T data){ this->data = data; }
};
If I implement the search Operation on this Linked list with the below prototype what should be the return value of the function. If T is a pointer, I can return NULL, but if T is a Complete object, what should be the return type, and how can i differentiate if T is a pointer or a Complete object. How can this search function works for T where T can be a pointer Or a complete object.
T List_search(T srch_data);
T List_search(T srch_data) {
ListNode<T> *curr = head;
while (curr) {
if (comp_fn.compare_data (curr->data, srch_data) == 0)
return curr->data;
curr = curr->right;
}
return NULL; <<< Compilation error if T is complete object
}
One option is to keep things simple: return the address of the found item, and nullptr if the item cannot be found:
template <typename T>
T* List_search(T srch_data)
{
ListNode<T> *curr = head;
while (curr)
{
if (comp_fn.compare_data (curr->data, srch_data) == 0)
return &curr->data;
curr = curr->right;
}
return nullptr;
}
The client would then check for a nullptr, and if it isn't a nullptr, can dereference the pointer.
For example, if the linked list node holds an int type:
int* foundData = List_search(10)
if ( foundData )
{
std::cout << *foundData;
}
Trying to finish my doublely linked list program, but I don't really know how to create a node using a class. I've only ever used sctructs.
DoubleNode.h:
#ifndef DOUBLE_NODE_H_
#define DOUBLE_NODE_H_
template<class ItemType>
class DoubleNode
{
private:
ItemType item;
DoubleNode<ItemType>* prev;
DoubleNode<ItemType>* next;
public:
DoubleNode(const ItemType& anItem, DoubleNode<ItemType>* prevPtr, DoubleNode<ItemType>* nextPtr);
~DoubleNode();
ItemType getItem() const;
DoubleNode<ItemType>* getPrev() const;
DoubleNode<ItemType>* getNext() const;
void setPrev(DoubleNode<ItemType>* prevPtr);
void setNext(DoubleNode<ItemType>* nextPtr);
};
#endif
DoubleNode.cpp:
#include "DoubleNode.h"
template<class ItemType>
DoubleNode<ItemType>::DoubleNode(const ItemType& anItem, DoubleNode<ItemType>* prevPtr, DoubleNode<ItemType>* nextPtr) :
item(anItem), prev(prevPtr), next(nextPtr)
{
}
template<class ItemType>
DoubleNode<ItemType>::~DoubleNode()
{
this->prev = this->next = nullptr;
}
template<class ItemType>
ItemType DoubleNode<ItemType>::getItem() const
{
return this->item;
}
template<class ItemType>
DoubleNode<ItemType>* DoubleNode<ItemType>::getPrev() const
{
return this->prev;
}
template<class ItemType>
DoubleNode<ItemType>* DoubleNode<ItemType>::getNext() const
{
return this->next;
}
template<class ItemType>
void DoubleNode<ItemType>::setPrev(DoubleNode<ItemType>* prevPtr)
{
this->prev = prevPtr;
}
template<class ItemType>
void DoubleNode<ItemType>::setNext(DoubleNode<ItemType>* nextPtr)
{
this->next = nextPtr;
}
These two files were provided by my professor, and I need to implement another class called DoubleListInterface.h. I'm working on that right now, but I don't really know if I've even created the nodes right.
Here's my DoubleList.cpp insertFront implementation so far:
template<class ItemType>
bool DoubleList<ItemType>::insertFront(const ItemType& newEntry)
{
DoubleNode<ItemType>* n; // Creating pointer to node
DoubleNode<ItemType>* head;
DoubleNode<ItemType>* tail;
// If list is empty, this is the first node
if (itemCount == 0){
n = new DoubleNode<ItemType>; // Creating node
n->this->item(newEntry); // Putting item in node
n->prev = NULL; // First node, so prev is null
head = n; // Both head and tail would be at this node
tail = n;
itemCount++; // Increment itemCount
}
else{
DoubleNode<ItemType>* temp = new node; // Creating a filling new node
temp->this->item(newEntry);
temp->this->setPrev(head->this->getPrev()); // Set prev to the prev of head pointer
temp->this->getNext() = this->head; // Make next point to the head
head->this->getPrev() = temp; // Point prev of the old head node to the newly created node
head = temp; // Temp is the new head
delete temp; // Delete temp pointer
temp = NULL;
itemCount++; // Increment intemCount
}
return true;
}
I get a lot of errors when I run this, the majority of which are "expected unqualified-id before 'this'" on every place that I use a this pointer. Don't really know what that means either, but I'd really like to know if I'm creating the nodes right. Thanks for anything you can contribute.
You can't point to this.
For example, you wrote
temp->this->item(newEntry);
The correct way to do this is
temp->item(newEntry);
I am very new to C++ templates. I am currently working on a project where I need to implement a Doubly Linked List using a template. Here is currently what I have so far:
template<class ItemType>
class SortedList
{
public:
SortedList();
~SortedList();
bool Insert (ItemType toAdd);
bool Delete (ItemType toDelete);
void Print();
private:
SortedList ( const SortedList & copyFrom );
SortedList & operator= ( const SortedList & assignFrom );
struct Node
{
Node ( ItemType item, Node * p = NULL, Node * n = NULL )
{ data = item; prev = p; next = n; }
ItemType data;
Node * prev, * next;
};
Node * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list == NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node * curr = list;
while ( curr != NULL )
{
Node * tempNext = curr->next;
delete current;
current = tempNext;
}
}
However, in my destructor for example, why can't I access the node elements? The code that is inside that method right now compiled, but does not throw errors. However if I try to use -> on curr, next or prev do not appear. Why do I not have access to these? I feel like I am missing something very obvious here to get started.
Also, how can I initialize list == NULL in the function head, instead of doing it outside of the class?
Don't know why it compiles, but you are using
delete current;
current = tempNext;
Instead of:
delete curr;
curr = tempNext;
Use inline initializer syntax:
class SortedList
{
public:
SortedList()
:
list(nullptr)
{ }
Use the same syntax to initialize Node (it's more optimal)
I'm building my own linked list class and I'm having some issues figuring out how to write some functions to help me traverse this list. This is my first time building a linked list from scratch, so if my approach is unconventional please let me know what might be more conventional.
I'd like write a function, within the List class that allows me to increment to the next element called getNext() as well as one that getPrev();
I wrote getNext like this:
T* getNext(){return next;}
However it tells me next is not declared within the scope. I'd also like to write a function that lets me access and modify the object within the list. I was considering using the bracket operator, but first I need to write a function to return the data member. Perhaps If I take a similar approach as I did within my pop functions.. thinking about it now. However, I'd still appreciate any advice.
Here is my List class:
#ifndef LIST_H
#define LIST_H
//List Class
template <class T>
class List{
struct Node {
T data;
Node *next;
Node *prev;
//Constructs Node Element
Node(T t, Node* p, Node* n) { data = (t); prev = (p); next = (n); }
// T *getNext() {return next;}
};
Node *head;
Node *tail;
public:
//Constructor
List() { head = NULL; tail=NULL; }
//Destructor
~List() {
while(head){
Node * temp(head);
head = head->next;
delete temp;
}
}
//is empty
bool empty() const {return (!head || !tail ); }
operator bool() const {return !empty(); }
//Push back
void push_back(T data) {
tail = new Node(data, tail, NULL);
if(tail->prev) //if the node in front of tail is initilized
tail->prev->next = tail;
if( empty() )
head = tail;
}
//Push front
void push_front(T data) {
head = new Node(data, NULL, head);
if(head->next)//if the node following head is initilized
head->next->prev = head;
if( empty() )
tail = head;
};
T pop_back() {
if( empty() )
throw("Error in List: List is empty\n");
Node* temp(tail);
T data(tail->data);
tail = tail->prev;
if( tail )
tail->next = NULL;
else
head = NULL;
delete temp;
return data;
}
T pop_front() {
if (empty())
throw("Error in List: List is empty\n");
Node* temp(head);
T data(head->data);
head = head->next;
if(head)
head->prev=NULL;
else
tail = NULL;
delete temp;
return data;
}
T getNext(){return next;}
};
#endif
getNext should be part of the struct Node and return a Node*
Node* getNext() { return next; }
Then from that you can get the value.
If you have to have it part of the list itself, which I would not recommend it will need to take a parameter of what Node you would like the next of:
Node* getNext(Node* n) {return n->next;}
Again, I recommend the first option.
Here is an approximate whole class with both of these:
template<typename T>
class List {
public:
struct Node {
Node* next, prev;
T data;
//some constructor and stuff
Node* Next() {return next;}
}
//some constructors and other functions
Node* getNext(Node* _n) {return _n->Next();}
}
then to use:
int main() {
List<int> l;
//add some stuff to the list
//get the head of the list
List<int>::Node* head = l.head; //or some corresponding function
//then
List<int>::Node* next = head->Next();
//or
List<int>::Node* next2 = l.getNext(head);
}
for starters getNext() should not return a pointer to the template class, it should return a pointer to the Node structure.
So it should be
Node* getNext(){return next;}
Because it's a member of Node struct and getNext is member of List. You should access it from an object of type Node.
creating some old data structures in C++. Currently I am having an issue with a doubly-linked list class:
List.h:
template <class T>
class List{
private:
int size;
struct listNode{
T data;
listNode* next;
listNode* prev;
listNode(T newData);
};
listNode * head;
listNode * tail;
listNode * curr;
listNode * find(listNode * place, int k);
void removeCurrent(listNode * temp);
public:
List();
int getSize() const;
void insert(int loc, T data);
void remove(int loc);
T const & getItem(int loc) const;
void print();
};
List.cpp:
#include "List.h"
#include <iostream>
using namespace std;
template<class T>
List<T>::List(){
size = 0;
head->next = tail;
head->prev = NULL;
tail->prev = head;
tail->next = NULL;
}
// getSize: public method that returns the size of the list
template<class T>
int List<T>::getSize() const {
return size;
}
// insert: public method that inserts data into the list
template<class T>
void List<T>::insert(int loc, T data){
if(loc <1){
cout<<"Invalid Location"<<endl;
return;
}
curr = find(head,loc-1);
listNode * newNode = new listNode(data);
newNode->next = curr->next;
newNode->prev = curr;
newNode->next->prev = newNode;
curr->next = newNode;
size++;
}
// remove: public method that inserts data into the list
template<class T>
void List<T>::remove(int loc){
if(loc <1){
cout<<"Invalid Location"<<endl;
return;
}
curr = find(head,loc); // Find the node infront of the target
removeCurrent(curr); // Remove that node
}
// removeCurrent: helper function that removes the current node
template<class T>
void List<T>::removeCurrent(listNode* temp){
listNode* t = temp->next;
temp->data = t->data; // HACK: take data from next node
temp->next = t->next;
t->next->prev = temp;
delete t;
t=NULL;
size--;
}
// find: private helper function that returns a pointer to the k-1 node
template<class T>
listNode * List<T>::find(listNode * place, int k){
if((k==0) || (place==NULL))
return place;
else return find(place->next,k-1);
}
// getItem: returns data at location loc
template<class T>
T const& List<T>::getItem(int loc) const{
curr = find(head,loc);
return curr->data;
}
// print: prints the sequence of variables in the list
template<class T>
void List<T>::print()
{
curr = head;
while(curr->next != tail){
curr = curr->next;
cout<<curr->data<<endl;
}
}
//listNode constructor
template<class T>
List<T>::listNode::listNode(T newdata):data(newdata),next(NULL),prev(NULL)
{}
The error I'm getting is the following:
error: 'listNode' does not name a type.
I have tried different suggestions offered in similar troubleshooting posts, but I'm still getting this error. I have a main.cpp that includes List.cpp, but it's practically empty.
You're going to have to specify which listNode you're talking about at the find method's return type because you defined it as a member of the List class and you're also going to have to use typename (because List<T> is a dependent scope).
template <class T>
typename List<T>::listNode* List<T>::find(listNode* place, int k)
{
if ((k == 0) || (place == NULL))
return place;
else
return find(place->next, k-1);
}
Assuming you're using c++11, you may also want to use nullptr instead of NULL since its safer and use the initializer list at the List constructor.