0

Possible Duplicate:
Why can templates only be implemented in the header file?

When I put my Stack.cpp into Stack.h it works just fine but, when I separate Stack.h,.cpp files it gives this error. I have also a main.cpp file which does nothing but includes AlgebraicExpression.h I use this command to compile : "g++ -o main main.cpp AlgebraicExpression.cpp Stack.cpp"

Undefined symbols for architecture x86_64:   "Stack<char>::pop()", referenced from:
      infix2postfix(char*) in ccKgncmm.o   "Stack<char>::top()", referenced from:
      infix2postfix(char*) in ccKgncmm.o   "Stack<char>::push(char)", referenced from:
      infix2postfix(char*) in ccKgncmm.o   "Stack<char>::size()", referenced from:
      infix2postfix(char*) in ccKgncmm.o   "Stack<char>::Stack()", referenced from:
      infix2postfix(char*) in ccKgncmm.o   "Stack<double>::pop()", referenced from:
      evaluatePostfix(char*) in ccKgncmm.o   "Stack<double>::top()", referenced from:
      evaluatePostfix(char*) in ccKgncmm.o   "Stack<double>::push(double)", referenced from:
      evaluatePostfix(char*) in ccKgncmm.o   "Stack<double>::Stack()", referenced from:
      evaluatePostfix(char*) in ccKgncmm.o ld: symbol(s) not found for architecture x86_64 collect2: ld returned 1 exit status

AlgebraicExpression.h

char* infix2postfix(char *infix);
double evaluatePostfix(char*);

Stack.h

#ifndef STACK_H
#define STACK_H

template <class T>
class Stack
{
public:
        Stack();
        void pop();
        T top();
        void push(T val);
        int size();

        T *values;
        int maxSize;
        int length;
};

#endif

AlgebraicExpression.cpp

#include "AlgebraicExpression.h"
#include "Stack.h"
using namespace std;
bool isOperator(char c)
{
        if(c=='+' || c=='-' ||
                c=='*' || c=='/')
                return true;
        return false;
}

bool isDigit(char c)
{
        if(c=='0'||(c>='1'&&c<='9'))
                return true;
        return false;
}

int compareOperators(char c1,char c2)
{
        int v1,v2;
        if(!isOperator(c1) || !isOperator(c2))
                return -1;
        if(c1 == '*' || c1 =='/')v1 = 1;
        else v1 = 0;
        if(c2 == '*' || c2 == '/')v2 = 1;
        else v2 = 0;

        return v1-v2;
}

char *infix2postfix(char *infix)
{
        int lenIn,lenPost;
        for(lenIn=0,lenPost=0;infix[lenIn];++lenIn)
                if(infix[lenIn]!='('&&infix[lenIn]!=')')
                        ++lenPost;

        char *postfix = new char[lenPost+1];
        int i,j;
        Stack<char> operations;

        for(i=0,j=0;i<lenIn&&j<lenPost;++i)
                if(isDigit(infix[i]))
                        postfix[j++] = infix[i];
                else if(isOperator(infix[i]))
                {
                        while(operations.size()&&
                                compareOperators(operations.top(),infix[i])>-1)
                        {
                                postfix[j++] = operations.top();
                                operations.pop();
                        }
                        operations.push(infix[i]);
                }
                else
                {
                        if(infix[i] == '(')
                                operations.push(infix[i]);
                        else if(infix[i] ==')')
                        {
                                while(operations.size()&&operations.top()!='(')
                                {
                                        postfix[j++] = operations.top();
                                        operations.pop();

                                }
                                operations.pop();
                        }
                }
        while(operations.size())
        {
                postfix[j++] = operations.top();
                operations.pop();
        }
        postfix[j] = '\0';
        return postfix;
}

double evaluatePostfix(char *postfix)
{
        Stack<double> result;
        for(int i=0;postfix[i];++i)
                if(isDigit(postfix[i]))
                        result.push(postfix[i]-'0');
                else
                {
                        double n1,n2,r;
                        n1 = result.top();
                        result.pop();
                        n2 = result.top();
                        result.pop();
                        if(postfix[i] == '+')
                                r = n1+n2;
                        else if(postfix[i] == '-')
                                r = n2-n1;
                        else if(postfix[i] == '*')
                                r = n1*n2;
                        else if(postfix[i] == '/')
                                r = n1/n2;
                        result.push(r);
                }
        return result.top();
}

Stack.cpp

#include "Stack.h"
template <class T>
Stack<T>::Stack()
{
        maxSize = 100;
        length =0;
        values = new T[maxSize];
}

template <class T>
T Stack<T>::top()
{
        return values[length-1];
}

template <class T>
void Stack<T>::push(T val)
{
        if(maxSize==length)
        {
                T *temp = new T[length*2];
                for(int i=0;i<length;++i)
                        temp[i] = values[i];
                values = temp;
                maxSize = length*2;
        }
        values[length++] = val;
}

template <class T>
void Stack<T>::pop()
{
        if(length>0)
                length--;
}

template <class T>
int Stack<T>::size()
{
        return length;
}
Community
  • 1
  • 1
mayy00
  • 224
  • 5
  • 14

2 Answers2

4

With class templates all the definitions need to be in the header itself.

C++ FAQ is a good read.

Basically when a template class is instantiated, it needs to be able to see the entire definition of the class and not just the header.

If you know all the types your class is going to be used with, you could instantiate the template with all those types and then leave the definition in the cpp, as explained in this C++ FAQ entry

As mentioned, this is also covered in Why can templates only be implemented in the header file?

Community
  • 1
  • 1
Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • 1
    It would be better if you can also point to http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – abnvp Jan 03 '13 at 05:30
  • thanks for the quick reply. this is my homework and teacher expects both Stack.h and Stack.cpp from me. so isn't there anyway to do it? – mayy00 Jan 03 '13 at 05:30
  • @mayy00 check the link posted by billz and me. The linked posts tells the ways to do that – abnvp Jan 03 '13 at 05:32
  • @abhinav that is a nice reference thanks. I didn't know that the problem was because of templates. I will check it now – mayy00 Jan 03 '13 at 05:33
  • @abhinav billz had already pointed to that, so i tried to cover other areas, let me add anyway. – Karthik T Jan 03 '13 at 06:25
2

If you really want to separate template header and implementation file, you could include Stack.cpp in the bottom of Stack.h, it's called The Inclusion Model

#include "Stack.cpp"

checkout the reference: Why can templates only be implemented in the header file?

Community
  • 1
  • 1
billz
  • 44,644
  • 9
  • 83
  • 100