Reputation: 94
I'm trying to create a stack using a linked list. I've already got it working using integers, but now I want to implement Templates to it. There are no errors detected before compile, but after running I get these errors:
*Undefined symbols for architecture x86_84: "Stack::printStack()", referenced from: _main in main.o
"Stack::pop()", referenced from: _main in main.o
"Stack::push(int)", referenced from: _main in main.o
"Stack::~Stack()", referenced from: _main in main.o
ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) *
I think my troubles come from having to define two templates, one in the Stack.h file and one in my LinkedList.h file. In my Stack.h file I need to call on Node, I can't call on Node without including the template arguments, and Stack.h won't recognize the template arguments without me including another template definition. Right now there are instances where I only use 'T' instead of Node, but I've tried it both ways. I feel like I've tried everything and I just can't figure out where my error is. I'm really just going for proof of concept at this point which is why I haven't added a copy constructor or additional functions for Stack. My code is below.
LinkedList.h
#ifndef Linked_List__Stack_LinkedList_h
#define Linked_List__Stack_LinkedList_h
template<class T>
struct Node {
public:
Node(Node *n, T data) : next(n), data(data) {}
Node *getNext() const { return next; }
T value() const { return data; }
private:
Node* next;
T data;
};
#endif
Stack.h
#ifndef __Linked_List__Stack__Stack__
#define __Linked_List__Stack__Stack__
#include "LinkedList.h"
#include <stdio.h>
#include <iostream>
using namespace std;
template <class T>
class Stack {
public:
Stack() : head(NULL), tail(NULL) {};
~Stack();
void push(T data);
T pop();
void printStack();
private:
Node<T> *head;
Node<T> *tail;
};
#endif /* defined(__Linked_List__Stack__Stack__) */
Stack.cpp
#include "Stack.h"
template <class T>
Stack<T>::~Stack() {
while (head) {
Node<T>* temp = head->getNext();
delete head;
head = temp;
}
head = tail = NULL;
}
template <class T>
void Stack<T>::push(T data) {
Node<T>* node = new Node<T>(head, data);
head = node;
if (head->getNext() == NULL )
tail = head;
}
template <class T>
T Stack<T>::pop() {
Node<T> *top = head;
T data;
if(head == NULL)
throw; //StackError(E_EMPTY);
data = head->value();
head = head->getNext();
delete top;
return data;
}
template <class T>
void Stack<T>::printStack() {
Node<T> *current = head;
while (current != tail) {
cout << current->value() << ", ";
current = current->getNext();
}
cout << current->value() << endl;
}
main.cpp
#include "Stack.h"
#include <iostream>
#include <stdexcept>
int main(int argc, const char * argv[]) {
Stack<int> *myIntStack = new Stack<int>();
myIntStack->push(10);
myIntStack->printStack();
myIntStack->pop();
myIntStack->printStack();
delete myIntStack;
return 0;
}
Upvotes: 0
Views: 266
Reputation: 40036
Almost no popular compiler allow you to put template definition in cpp file as a separated compilation unit (hence the linker errors).
In brief, just move the content of your Stack.cpp into Stack.h (and forget about your Stack.cpp) then everything should work.
Another way I like to use (well... over ten years ago when I am still writing C++ in my job), is to "include" the template source in the header, like:
Foo.h
#ifndef FOO_H__
#define FOO_H__
TEMPLATE_DECL template <class T> Foo {
....
};
#ifndef SUPPORT_TEMPLATE_EXPORT
#include "Foo.tmpl" // include it if you CANNOT compile it as separate compilation unit
#endif
#endif //ifndef FOO_H__
Foo.tmpl (I use another extension to differ it from .cpp)
#ifdef SUPPORT_TEMPLATE_EXPORT
#include "Foo.h" // only include if you can compile it as separate compilation unit
#endif
// template definition
TEMPLATE_DEF Foo<T>::bar() {....}
Of course you need to take care of the preprocessor and compiler setup but that should be trivial. And, template export is deprecated from C++0x, this approach can be further simplified if you are not care about using this feature in older compiler (e.g. Comenu)
Something off-topic: Avoid using namespace (or any using clause in fact) in your headers. It is going to cause namespace pollution.
Upvotes: 3
Reputation: 1812
As Adrian points out, the compiler needs to have all the template implementation available to it at instantiation time, and I agree with his suggestion to simply move the implementation into Stack.h
.
However, if you want to keep interface and implementation separate for your own purposes, you can #include "Stack.cpp"
at the bottom of Stack.h
(and remove the #include "Stack.h"
from Stack.cpp
).
Upvotes: 0