This question already has answers here:
Why do I get "unresolved external symbol" errors when using templates? [duplicate]
(3 answers)
Undefined reference to template members
(1 answer)
Closed 10 years ago.
I always get
undefined reference to `Graph::InsertVertex(std::string)'
if I compile my project! Any hints why he cant resolve this reference?
(all Files are in the netbeans project folder)
// main.cpp
#include <cstdlib>
#include <string>
#include "Graph.h"
using namespace std;
int main(int argc, char** argv)
{
Graph<string> *graph = new Graph<string>(); // <--- ERROR
graph->InsertVertex("A");
return 0;
}
// Node.h
#include <iostream>
#include "Graph.h"
template<class T>
class Node
{
friend class Graph;
public:
Node(T val)
{
this->data = val;
this->vertList = NULL;
this->next = NULL;
}
Node(const Node& orig);
virtual ~Node();
private:
T data;
Node<T> *vertList;
Node<T> *next;
int status;
};
// Graph.h
#include <iostream>
#include "Node.h"
template <class T>
class Graph
{
public:
Graph()
{
head = NULL;
}
void InsertVertex(T val);
void InsertEdge(T v_val, T e_val);
void PrintVertices();
void PrintEdges(T v_val);
void DeleteEdge(T v_val, T e_val);
void DeleteVertex(T val);
void bfs();
private:
Node<T> *head;
};
// Graph.cpp
#include "Graph.h"
template <class T>
void Graph<T>::InsertVertex(T val)
{
Node<T> *temp = new Node<T>(val);
if(head == NULL) head = temp;
else
{
Node<T> node = head;
while(node->vertList != NULL)
node = node->vertList;
node->vertList = temp;
}
}
template <class T>
void Graph<T>::InsertEdge(T v_val, T e_val)
{
if (head != NULL)
{
Node<T> *k = head;
Node<T> *t = head;
Node<T> *temp = new Node<T> (e_val);
while (t != NULL)
{
if (t->data == v_val)
{
Node<T> *s = t;
while (s->next != NULL)
s = s->next;
s->next = temp;
while (k != NULL)
{
if(k->data == e_val) break;
k = k->vertList;
}
temp->vertList = k;
return;
}
t = t->vertList;
} // end while loop
}
else std::cout << "Add first vertices to the graph" << std::endl;
}
template <class T>
void Graph<T>::PrintEdges(T v_val)
{
Node<T>* t = head;
while (t != NULL)
{
if (t->data == v_val)
{
while (t->next != NULL)
{
std::cout << t->next->vertList->data << " ";
t = t->next;
}
}
t = t->vertList;
}
}
template <class T>
void Graph<T>::PrintVertices()
{
Node<T>* t = head;
while (t != NULL)
{
std::cout << t->data << " ";
t = t->vertList;
}
}
Typically you want your template methods in the header, so they are compiled when needed. In case you really want to hide it in the implementation file, you have to explicitly instantiate the template in Graph.cpp like
template class Graph<string>;
Since you have to do that for every type T you intend to use with Graph<T>, the point of the template class is somewhat defeated and you better put everything into the header
You need to define member functions in a header file, because when instantiating a template, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument.
In your example:
template <class T>
class Graph {
public:
void InsertVertex(T val) {
Node<T> *temp = new Node<T>(val);
if(head == NULL)
head = temp;
// ...
}
// ...
private:
Node<T> *head;
};
Related
when I try to implement a Binary tree with a few essential functions, there were no error pop up. However, when I initialize the tree and try to use its functions, there's a compile error showing, and I don't know how to fix it, can you help me. The following is my code and the error that shows:
Edit: I fix the problem by changing the argument of addItem(T& item) to addItem(const T& item). Thank you for your help!
Node.h
#ifndef BINARYTREE_NODE_H
#define BINARYTREE_NODE_H
template <class T>
class Node {
public:
Node<T>* left;
Node<T>* right;
T data;
};
BinaryTree.h
#ifndef BINARYTREE_BINARYTREE_H
#define BINARYTREE_BINARYTREE_H
#include "Node.h"
enum Traversal
{
INORDER,
POSTORDER,
PREORDER
};
template <class T>
class BinaryTree {
private:
Node<T>* root;
int size = 0;
Traversal currentTraversal;
void inOrder(Node<T>* parent,void f(T&));
void preOrder(Node<T>* parent,void f(T&));
void postOrder(Node<T>* parent,void f(T&));
Node<T>* insert(Node<T>* parent, T item);
public:
void setTraversal(Traversal order);
void addItem(const T& item);
BinaryTree();
void print(T& item);
};
#include "BinaryTree.cpp"
#endif //BINARYTREE_BINARYTREE_H
BinaryTree.cpp
#ifndef BINARYTREE_BINARYTREE_CPP
#define BINARYTREE_BINARYTREE_CPP
#include <iostream>
#include "BinaryTree.h"
template <class T>
BinaryTree<T>::BinaryTree() {
root = nullptr;
}
template <class T>
Node<T>* BinaryTree<T>::insert(Node<T> *parent, T item) {
if(parent == nullptr)
{
Node<T>* temp = new Node<T>;
temp->data = item;
return temp;
}
else if(parent->data > item)
{
if (parent->left != nullptr)
insert(parent->left,item);
else{
parent->left = new Node<T>;
parent->left->data = item;
parent->left->left = nullptr;
parent->left->right = nullptr;
}
}
else if (parent->data <= item)
{
if (parent->right != nullptr)
insert(parent->right,item);
else{
parent->right = new Node<T>;
parent->right->data = item;
parent->right->left = nullptr;
parent->right->right = nullptr;
}
}
}
template <class T>
void BinaryTree<T>::addItem(constT &item) {
insert(root,item);
size++;
}
template <class T>
void BinaryTree<T>::inOrder(Node<T> *parent, void f(T&))
{
if (parent != nullptr)
{
inOrder(f, parent->left);
f(parent->data);
inOrder(f,parent->right);
}
}
template <class T>
void BinaryTree<T>::preOrder(Node<T> *parent, void f(T&)) {
if (parent != nullptr)
{
f(parent->data);
preOrder(f,parent->left);
preOrder(f,parent->right);
}
}
template <class T>
void BinaryTree<T>::postOrder(Node<T> *parent, void f(T&)) {
if (parent != nullptr)
{
postOrder(f,parent->left);
postOrder(f,parent->right);
f(parent->data);
}
}
template <class T>
void BinaryTree<T>::print(T& item)
{
std::cout << item <<std::endl;
if(currentTraversal == PREORDER)
preOrder(root,print(item));
if (currentTraversal == POSTORDER)
postOrder(root,print(item));
if(currentTraversal == INORDER)
inOrder(root,print(item));
}
template <class T>
void BinaryTree<T>::setTraversal(Traversal order) {
currentTraversal = order;
}
#endif
main.cpp
#include <iostream>
#include "BinaryTree.h"
int main() {
BinaryTree<int> tree;
tree.addItem(2); // Here's the error showing: "Non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'"
}
You have:
T &item
As the argument to addItem(). It should either be a const reference or a plain value. That is, const T & or T.
For more on why this is the case, see: How come a non-const reference cannot bind to a temporary object?
I am trying to make a Generic Linked list in C++ using templates. But i am getting this error 'GenericNode::{ctor}': constructors not allowed a return type through which i can't possibly know what am i doing wrong?
PS. i have also gone through other posts here on Stack Overflow which says that the error is due to the missing semi-colon after the class definition but i think i don't have a 'missing semi-colon' case. Any help?
Code :
GenericLinkedList.h :
#pragma once
template <typename Datatype>
class GenericNode {
Datatype T;
GenericNode *next;
public:
GenericNode() {}
GenericNode(Datatype T);
};
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
template <typename Datatype>
class GenericLinkedList {
GenericNode *Data;
public:
GenericLinkedList() {
Data = NULL;
}
int isEmpty();
void addDataAtFront(Datatype data);
void addDataAtEnd(Datatype data);
void print();
};
template <typename Datatype>
int GenericLinkedList<Datatype>::isEmpty() {
return Data == NULL;
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtFront(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
Data = newNode;
Data->next = tmpNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtEnd(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
while (tmpNode->next != NULL) {
tmpNode = tmpNode->next;
}
tmpNode->next = newNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::print() {
GenericNode tmpNode;
tmpNode = Data;
for (tmpNode;tmpNode != NULL;tmpNode = tmpNode->next) {
cout << tmpNode->T << " ";
}
}
.cpp :
#include <iostream>
#include <conio.h>
#include "GenericLinkedList.h"
using namespace std;
int main() {
GenericLinkedList<int> T;
T.addDataAtFront(5);
T.addDataAtEnd(6);
T.addDataAtFront(4);
T.print();
_getch();
}
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
You write the return type void. It's a constructor.
void GenericNode::GenericNode(Datatype data)
remove void its a constructor. Constructors don't return and dont have a return type.
I have a problem with creating base class for DoubleLinkedList.
Right now it's giving me this error
/tmp/cc3lORia.o:(.rodata._ZTV24AbstractDoubleLinkedListIiE[_ZTV24AbstractDoubleLinkedListIiE]+0x10):
undefined reference to
`AbstractDoubleLinkedList::createNewNode(int)' collect2: error:
ld returned 1 exit status
I've tried this and that as you can see by commented lines in code, but none of it works.
So how to define abstract template class with abstract method (factory method by the way) and then redefine it in children classes?
/*
* AbstractDoubleLinkedList.hpp
*
* Created on: Mar 2, 2015
* Author: michael
*/
#ifndef ABSTRACTDOUBLELINKEDLIST_H_
#define ABSTRACTDOUBLELINKEDLIST_H_
#include <vector>
using namespace std;
template <class T> class ListNode {
private:
void init();
public:
ListNode();
ListNode(T value);
ListNode *previous;
ListNode *next;
T value;
};
template <class T> void ListNode<T>::init() {
previous = nullptr;
next = nullptr;
}
template <class T> ListNode<T>::ListNode() {
init();
}
template <class T> ListNode<T>::ListNode(T value) {
init();
this->value = value;
}
template <class T> class AbstractDoubleLinkedList {
private:
void pullOutNode(ListNode<T> *node);
protected:
virtual ListNode<T>* createNewNode(T element);
public:
AbstractDoubleLinkedList();
void push_back(T element);
T front();
T back();
void insertBefore(ListNode<T> *node, ListNode<T> *beforeNode);
void insertAfter(ListNode<T> *node, ListNode<T> *afterNode);
void moveNodeAfter(ListNode<T> *node, ListNode<T> *afterNode);
vector<T> toVector();
ListNode<T> *frontNode;
ListNode<T> *backNode;
};
template <class T> void AbstractDoubleLinkedList<T>::push_back(T element) {
ListNode<T>* node = createNewNode(element);
node->previous = backNode;
if (backNode != nullptr) {
backNode->next = node;
node->previous = backNode;
}
else {
frontNode = node;
}
backNode = node;
}
template <class T> void AbstractDoubleLinkedList<T>::pullOutNode(ListNode<T> *node) {
if (node != frontNode) {
node->previous->next = node->next;
}
else {
frontNode = node->next;
}
if (node != backNode) {
node->next->previous = node->previous;
}
else {
backNode = node->previous;
}
}
template <class T> T AbstractDoubleLinkedList<T>::front() {
return frontNode->value;
}
template <class T> T AbstractDoubleLinkedList<T>::back() {
return backNode->value;
}
template <class T> void AbstractDoubleLinkedList<T>::insertAfter(ListNode<T> *node, ListNode<T> *afterNode) {
node->previous = afterNode;
node->next = afterNode->next;
afterNode->next = node;
if (afterNode == backNode) {
backNode = node;
}
}
template <class T> void AbstractDoubleLinkedList<T>::insertBefore(ListNode<T> *node, ListNode<T> *beforeNode) {
node->next = beforeNode;
beforeNode->previous->next = node;
beforeNode->previous = node;
if (beforeNode == frontNode) {
frontNode = node;
}
}
template <class T> void AbstractDoubleLinkedList<T>::moveNodeAfter(ListNode<T> *node, ListNode<T> *afterNode) {
pullOutNode(node);
node->previous = afterNode;
node->next = afterNode->next;
if (node->next == nullptr) {
backNode = node;
}
afterNode->next = node;
}
template <class T> vector<T> AbstractDoubleLinkedList<T>::toVector() {
ListNode<T>* node = frontNode;
vector<int> listAsVector;
bool shouldHaveAnother = (frontNode != nullptr);
while(shouldHaveAnother) {
listAsVector.push_back(node->value);
if (node->next != nullptr)
node = node->next;
else {
shouldHaveAnother = false;
}
}
return listAsVector;
}
template <class T> AbstractDoubleLinkedList<T>::AbstractDoubleLinkedList() {
frontNode = nullptr;
backNode = nullptr;
}
#endif /* ABSTRACTDOUBLELINKEDLIST_HPP_ */
/*
* DoubleLinkedList.hpp
*
* Created on: Feb 26, 2015
* Author: michael
*/
#ifndef DOUBLELINKEDLIST_HPP_
#define DOUBLELINKEDLIST_HPP_
#include "AbstractDoubleLinkedList.hpp"
template <class T> class DoubleLinkedList : public AbstractDoubleLinkedList<T> {
protected:
ListNode<T>* createNewNode(T element) {
return new ListNode<T>(element);
}
public:
~DoubleLinkedList() {
ListNode<T>* node = this->backNode;
bool shouldHaveAnother = (node != nullptr);
while(shouldHaveAnother) {
ListNode<T>* ptr = node->previous;
delete node;
if (ptr != nullptr)
node = ptr;
else {
shouldHaveAnother = false;
}
}
};
};
//template <class T> ListNode<T> DoubleLinkedList<T>::createNewNode(T element) {
// return new ListNode<T>(element);
//}
//template <class T> DoubleLinkedList<T>::~DoubleLinkedList() {
//
// ListNode<T>* node = this->backNode;
// bool shouldHaveAnother = (node != nullptr);
// while(shouldHaveAnother) {
// ListNode<T>* ptr = node->previous;
// delete node;
// if (ptr != nullptr)
// node = ptr;
// else {
// shouldHaveAnother = false;
// }
// }
//}
#endif /* DOUBLELINKEDLIST_HPP_ */
EDIT1:
So, there is a question "Why do I need my own container class and why not use list or vector?"
I need a data structure with constant time random access and constant time deletion and insertion. BUT I've already tried std::unordered_set and It's not good enough (while technically it meets the requirements) because of allocations and deallocations of memory (when deleting and inserting)
So I figured another way. I want to use a linked list with one "guard" element and the end. When I need to "delete" element from it I would move it after guard. And to check if list is "empty" I would check if the first element is the guard element. But I need a constant-time random access. This can be achieved by map of pointers to every element.
But to achieve maximum performance I need to also minimize cache misses. And I thinks that std::list would be scattered across the memory, because it is the normal behaviour for it. So I figured that the only way to do so - is to allocate vector> and then use this preallocated nodes to new elements.
So am I wrong somewhere? Can I achieve maximum performance more easier?
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 8 years ago.
Here is my code.
First I defined two class:
#include <iostream>
using namespace std;
template<class Datatype>
class Node
{
public:
Node()
{
next = NULL;
prev = NULL;
}
Node* getNext() const
{
return next;
}
Node* getPrev() const
{
return prev;
}
Datatype* getData() const
{
return &data;
}
void changeNext()
{
next = NULL;
}
void changeNext(Node& nextNode)
{
next = &nextNode;
}
void changePrev()
{
prev = NULL;
}
void changePrev(Node& prevNode)
{
prev = &prevNode;
}
Node* addNext(Node &);
Node* addPrev(Node &);
void nodeDel();
void addData(Datatype &);
private:
Node* next;
Node* prev;
Datatype data;
};
template<class Datatype>
class Stack
{
public:
int push(Datatype &);
Datatype pop();
Datatype* peek();
private:
Node<Datatype> node;
};
This file is called my_node.h. The defines of some functions are in the other file, called my_node.cpp. It is like this:
#include "my_node.h"
using namespace std;
template <class Datatype>
Node<Datatype>* Node<Datatype>::addNext(Node<Datatype>& new_node)
{
if (next == NULL)
{
changeNext(new_node);
new_node.changePrev(*this);
}
else
{
Node* next = getNext();
changeNext(new_node);
new_node.changePrev(*this);
next -> changePrev(new_node);
new_node.changeNext(*next);
}
return &new_node;
}
template <class Datatype>
Node<Datatype>* Node<Datatype>::addPrev(Node<Datatype>& new_node)
{
if (prev == NULL)
{
changePrev(new_node);
new_node.changeNext(*this);
}
else
{
Node* prev = getPrev();
changePrev(new_node);
new_node.changeNext(*this);
prev -> changeNext(new_node);
new_node.changePrev(*prev);
}
return &new_node;
}
template<class Datatype>
void Node<Datatype>::nodeDel()
{
if (prev == NULL && next == NULL)
;
else if (prev == NULL)
{
Node* next = getNext();
next -> changePrev();
}
else if (next == NULL)
{
Node* prev = getPrev();
prev -> changeNext();
}
else
{
Node* next = getNext();
Node* prev = getPrev();
next -> changePrev(*prev);
prev -> changeNext(*next);
}
delete this;
return;
}
template <class Datatype>
void Node<Datatype>::addData(Datatype &new_data)
{
data = new_data;
}
template <class Datatype>
int Stack<Datatype>::push(Datatype &new_data)
{
Node<Datatype> *pt_node = new Node<Datatype>;
if (pt_node == NULL)
return -1;
Datatype *pt_data;
pt_data = (this -> node).getData();
pt_node -> addData(*pt_data);
(this -> node).addData(new_data);
pt_node -> addNext(this -> node);
}
template <class Datatype>
Datatype Stack<Datatype>::pop()
{
Datatype temp((this -> node).data);
Datatype* new_fir = ((this -> node).getNext()) -> getData();
(this -> node).addData(*new_fir);
((this -> node).getNext())->nodeDel();
return temp;
}
template <class Datatype>
Datatype* Stack<Datatype>::peek()
{
return (this->node).getData();
}
So above, I declare class in .h file and define some function of those classes in .cpp file.
Now, I wrote a test file to test how it works. Test file test.cpp is like this:
#include <iostream>
#include "my_node.h"
using namespace std;
int main()
{
Stack<float> test_stack;
float a = 2.3;
float b = 3.4;
test_stack.push(a);
test_stack.push(b);
cout << test_stack.pop();
cout << test_stack.pop();
return 0;
}
The command I use is simply:
g++ -g -Wall my_node.cpp test.cpp -o test
The compiling error is like this:
/tmp/ccYaX0on.o: In function `main':
/home/user/cpp/oop_eg/test.cpp:11: undefined reference to `Stack<float>::push(float&)'
/home/user/cpp/oop_eg/test.cpp:12: undefined reference to `Stack<float>::push(float&)'
/home/user/cpp/oop_eg/test.cpp:14: undefined reference to `Stack<float>::pop()'
/home/user/cpp/oop_eg/test.cpp:15: undefined reference to `Stack<float>::pop()'
collect2: ld returned 1 exit status
I feel so strange because I defined all those functions.
Thanks,
Kevin Zhou
With templates, you generally have to put the whole thing (declaration and definition) into a header file. That's because the code which uses the template needs to see the definition in order to instantiate it.
Basically, you can probably just cut+paste all the functions from my_node.cpp into my_node.h.
I know there are a lot of similar questions out there - believe me, I've read them - but I can't get this to work. Which is peculiar, because I resolved a similar struggle with a related program just the other day. I realize that the answer to my question quite likely is out there somewhere, but I've spent a good hour or two looking, without much success.
I am trying to build a linked list. The program consists of four files - header files for the linked list and the node, as well as an interace to the list, and the .cpp file containing the main method.
ListTester.cpp
#include "StdAfx.h"
#include "LinkedList.h"
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void main() {
LinkedList<int> a;
a.addFirst(22);
a.addFirst(24);
a.addFirst(28);
LinkedList<int> b;
b = a;
b = b + a;
b += a;
cout<<b;
}
LinkedList.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include "List.h"
#include <ostream>
template <typename T>
class LinkedList : public List {
private:
int n;
Node<T> *first;
Node<T> *last;
public:
LinkedList();
LinkedList(const LinkedList & ll);
~LinkedList();
int size();
void clear();
void addFirst(T data);
void addLast(T data);
T removeFirst();
T removeLast();
T getFirst();
T getLast();
Node<T>* getFirstNode() const;
void addAt(int pos, T data);
T removeAt(int pos);
T getAt(int pos);
LinkedList& operator=(const LinkedList<T> &right);
T operator[](int i);
LinkedList& operator+(const LinkedList<T> &right);
LinkedList& operator+=(const LinkedList<T> &right);
friend std::ostream& operator<<(std::ostream &os, const LinkedList<T> & ll);
};
template <typename T>
LinkedList<T>::LinkedList() {
this->n = 0;
this->first = 0;
this->last = 0;
}
template <typename T>
LinkedList<T>::LinkedList(const LinkedList & ll) {
this-> n = 0;
this-> first = 0;
this-> last = 0;
Node *temp = ll.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
}
template <typename T>
void LinkedList<T>::addFirst(T data) {
Node *p = new Node(data, first);
first = p;
if(!n)
last = p;
n++;
}
template <typename T>
void LinkedList<T>::addLast(T data) {
Node *p = new Node(data, 0);
if(!n)
first = last = p;
else {
last->next = p;
last = p;
}
n++;
}
template <typename T>
T LinkedList<T>::removeFirst() {
T a = 0;
if(!n)
throw "Can't retrieve element from empty list!";
a = first->getData();
Node *p = first->next;
delete first;
first = p;
n--;
return a;
}
template <typename T>
T LinkedList<T>::removeLast() {
T a = 0;
if(!n)
throw "Can't retrieve element from empty list!";
if(n == 1) {
a = last->getData();
delete first;
first = last = 0;
}
else {
a = last->getData();
Node *p = first;
while(p->next->next != 0)
p = p->next;
delete p->next;
p->next = 0;
last = p;
}
n--;
return a;
}
template <typename T>
T LinkedList<T>::getFirst() {
if(n < 1)
throw "Can't retrieve element from empty list!";
return first->getData();
}
template <typename T>
T LinkedList<T>::getLast() {
if(n < 1)
throw "Can't retrieve element from empty list!";
return last->getData();
}
template <typename T>
Node<T>* LinkedList<T>::getFirstNode() const {
return first;
}
template <typename T>
int LinkedList<T>::size() {
return n;
}
template <typename T>
T LinkedList<T>::getAt(int pos) {
if(pos >= n)
throw "Element index out of bounds!";
Node *temp = first;
while(pos > 0) {
temp = temp->next;
pos--;
}
return temp->getData();
}
template <typename T>
void LinkedList<T>::clear() {
Node *current = first;
while(current) {
Node *next = current->next;
delete current;
if(next)
current = next;
else
current = 0;
}
}
template <typename T>
void LinkedList<T>::addAt(int pos, T data) {
if(pos >= n)
throw "Element index out of bounds!";
if(pos == 0)
addFirst(data);
else {
Node *temp = first;
while(pos > 1) {
temp = temp->next;
pos--;
}
Node *p = new Node(data, temp->next);
temp-> next = p;
n++;
}
}
template <typename T>
T LinkedList<T>::removeAt(int pos) {
if(pos >= n)
throw "Element index out of bounds!";
if(pos == 0)
return removeFirst();
if(pos == n - 1)
return removeLast();
else {
Node *p = first;
while(pos > 1) {
p = p->next;
pos--;
}
T a = p->next->getData();
Node *temp = p->next;
p->next = p->next->next;
delete temp;
n--;
return a;
}
}
template <typename T>
LinkedList<T>::~LinkedList() {
clear();
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T> &right) {
if(this != &right) {
n = 0;
first = 0;
last = 0;
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
}
return *this;
}
template <typename T>
T LinkedList<T>::operator[](int i) {
return getAt(i);
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator+(const LinkedList<T> &right) {
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
return *this;
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator+=(const LinkedList<T> &right) {
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
return *this;
}
template <typename T>
std::ostream& operator<<(std::ostream &os, const LinkedList<T> &ll) {
Node *temp = ll.getFirstNode();
while(temp) {
os<<temp->getData()<<std::endl;
temp = temp->getNext();
}
return os;
}
#endif
Node.h
#ifndef NODE_H
#define NODE_H
template <typename T>
class Node {
private:
T data;
public:
Node<T>* next;
T getData();
Node<T>* getNext();
Node(T data, Node<T>* next);
Node(const Node & n);
};
template <typename T>
T Node<T>::getData() {
return data;
}
template <typename T>
Node<T>* Node<T>::getNext() {
return next;
}
template <typename T>
Node<T>::Node(T data, Node<T>* next) {
this->data = data;
this->next = next;
}
template <typename T>
Node<T>::Node(const Node & n) {
data = n.data;
next = n.next;
}
#endif
List.h
#ifndef LIST_H
#define LIST_H
class List
{
public:
virtual void addFirst(int data) = 0;
virtual void addAt(int pos, int data) = 0;
virtual void addLast(int data) = 0;
virtual int getFirst()= 0;
virtual int getAt(int pos) = 0;
virtual int getLast()= 0;
virtual int removeFirst()= 0;
virtual int removeAt(int pos) = 0;
virtual int removeLast()= 0;
virtual int size() = 0;
virtual void clear() = 0;
virtual ~List() {};
};
#endif
For this, I get LNK2019 and LNK1120 linking errors. I know I used to get this when implementing a Queue in separated .h and .cpp files. But worked around it by doing everything in the header. I also know that this can happen when not implementing a named method, but I can't find any of those here. So what's causing this? I wish the compiler / IDE could point me to the possible cause of the error. But then again, if it was an easy task to find the faulty line, I assume it would already do this. VS 2012 btw.
You made main a function template. Not only does this not make sense (there is no mention of the template parameter inside), it's also never instantiated (and even if it was, it probably wouldn't resolve to the correct main that a program needs as a start point).
Furthermore, it should be int main rather than void main.
// template <typename T>
void main() {
LinkedList<int> a;
a.addFirst(22);
a.addFirst(24);
a.addFirst(28);
LinkedList<int> b;
b = a;
b = b + a;
b += a;
cout<<b;
}
You need a main function, not a main function template. That's probably the source of your linker error: no function called "main".
The reason this won't work is primarily because class templates and function templates are never expanded to real code unless they're used. Since main is the entrypoint to your program, you never call main from anywhere and thus no code for main is ever generated.
Furthermore due to the name mangling that C++ compilers do to functions (to handle overloading, templates, namespaces etc) the symbol that will be generated in the resulting assembly for this main template probably won't be the right one. If it's looking for a symbol 'main' and it sees
$__T_float_main_blah_blah_blah
then you won't link anyways. Long story short: main is a function, not a function template.