Chris Searcy
Chris Searcy

Reputation: 94

Getting "symbols not found" errors implementing a Stack as Linked List using templates

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

Answers (2)

Adrian Shum
Adrian Shum

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

Derek T. Jones
Derek T. Jones

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

Related Questions